Span trace utilities and runner source hint
This commit is contained in:
@ -12,11 +12,7 @@ use crate::mir::MirCompiler;
|
||||
use crate::parser::NyashParser;
|
||||
|
||||
fn require_experiment_toggle() -> bool {
|
||||
if std::env::var("NYASH_JOINIR_EXPERIMENT")
|
||||
.ok()
|
||||
.as_deref()
|
||||
!= Some("1")
|
||||
{
|
||||
if std::env::var("NYASH_JOINIR_EXPERIMENT").ok().as_deref() != Some("1") {
|
||||
eprintln!(
|
||||
"[joinir/runner] NYASH_JOINIR_EXPERIMENT=1 not set, skipping experimental runner test"
|
||||
);
|
||||
@ -50,8 +46,7 @@ static box Runner {
|
||||
"#;
|
||||
let full_src = format!("{src}\n{runner}");
|
||||
|
||||
let ast: ASTNode =
|
||||
NyashParser::parse_from_string(&full_src).expect("skip_ws: parse failed");
|
||||
let ast: ASTNode = NyashParser::parse_from_string(&full_src).expect("skip_ws: parse failed");
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let compiled = mc.compile(ast).expect("skip_ws: MIR compile failed");
|
||||
|
||||
@ -113,8 +108,7 @@ static box Runner {
|
||||
"#;
|
||||
let full_src = format!("{func_scanner_src}\n{test_src}\n{runner}");
|
||||
|
||||
let ast: ASTNode =
|
||||
NyashParser::parse_from_string(&full_src).expect("trim_min: parse failed");
|
||||
let ast: ASTNode = NyashParser::parse_from_string(&full_src).expect("trim_min: parse failed");
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let compiled = mc.compile(ast).expect("trim_min: MIR compile failed");
|
||||
|
||||
|
||||
@ -14,11 +14,7 @@ use crate::mir::join_ir::*;
|
||||
use crate::mir::join_ir_runner::{run_joinir_function, JoinValue};
|
||||
|
||||
fn require_experiment_toggle() -> bool {
|
||||
if std::env::var("NYASH_JOINIR_EXPERIMENT")
|
||||
.ok()
|
||||
.as_deref()
|
||||
!= Some("1")
|
||||
{
|
||||
if std::env::var("NYASH_JOINIR_EXPERIMENT").ok().as_deref() != Some("1") {
|
||||
eprintln!(
|
||||
"[joinir/runner/standalone] NYASH_JOINIR_EXPERIMENT=1 not set, skipping standalone test"
|
||||
);
|
||||
@ -161,7 +157,10 @@ fn joinir_runner_standalone_trim() {
|
||||
)
|
||||
.expect("trim runner failed");
|
||||
match result {
|
||||
JoinValue::Str(s) => assert_eq!(s, "abc ", "simplified trim should remove only leading spaces"),
|
||||
JoinValue::Str(s) => assert_eq!(
|
||||
s, "abc ",
|
||||
"simplified trim should remove only leading spaces"
|
||||
),
|
||||
other => panic!("trim returned non-string: {:?}", other),
|
||||
}
|
||||
|
||||
@ -209,12 +208,14 @@ fn build_skip_ws_joinir() -> JoinModule {
|
||||
let mut entry_func = JoinFunction::new(entry_id, "skip_ws_entry".to_string(), vec![s_param]);
|
||||
|
||||
// n = s.length()
|
||||
entry_func.body.push(JoinInst::Compute(MirLikeInst::BoxCall {
|
||||
dst: Some(n_var),
|
||||
box_name: "StringBox".to_string(),
|
||||
method: "length".to_string(),
|
||||
args: vec![s_param],
|
||||
}));
|
||||
entry_func
|
||||
.body
|
||||
.push(JoinInst::Compute(MirLikeInst::BoxCall {
|
||||
dst: Some(n_var),
|
||||
box_name: "StringBox".to_string(),
|
||||
method: "length".to_string(),
|
||||
args: vec![s_param],
|
||||
}));
|
||||
|
||||
// i_init = 0
|
||||
entry_func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
@ -360,12 +361,14 @@ fn build_trim_joinir() -> JoinModule {
|
||||
let mut entry_func = JoinFunction::new(entry_id, "trim_entry".to_string(), vec![s_param]);
|
||||
|
||||
// n = s.length()
|
||||
entry_func.body.push(JoinInst::Compute(MirLikeInst::BoxCall {
|
||||
dst: Some(n_var),
|
||||
box_name: "StringBox".to_string(),
|
||||
method: "length".to_string(),
|
||||
args: vec![s_param],
|
||||
}));
|
||||
entry_func
|
||||
.body
|
||||
.push(JoinInst::Compute(MirLikeInst::BoxCall {
|
||||
dst: Some(n_var),
|
||||
box_name: "StringBox".to_string(),
|
||||
method: "length".to_string(),
|
||||
args: vec![s_param],
|
||||
}));
|
||||
|
||||
// const_0 = 0
|
||||
entry_func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
@ -383,12 +386,14 @@ fn build_trim_joinir() -> JoinModule {
|
||||
});
|
||||
|
||||
// result = s.substring(start, n)
|
||||
entry_func.body.push(JoinInst::Compute(MirLikeInst::BoxCall {
|
||||
dst: Some(result_var),
|
||||
box_name: "StringBox".to_string(),
|
||||
method: "substring".to_string(),
|
||||
args: vec![s_param, start_var, n_var],
|
||||
}));
|
||||
entry_func
|
||||
.body
|
||||
.push(JoinInst::Compute(MirLikeInst::BoxCall {
|
||||
dst: Some(result_var),
|
||||
box_name: "StringBox".to_string(),
|
||||
method: "substring".to_string(),
|
||||
args: vec![s_param, start_var, n_var],
|
||||
}));
|
||||
|
||||
// return result
|
||||
entry_func.body.push(JoinInst::Ret {
|
||||
|
||||
@ -21,14 +21,8 @@ use crate::mir::MirCompiler;
|
||||
use crate::parser::NyashParser;
|
||||
|
||||
fn require_experiment_toggle() -> bool {
|
||||
if std::env::var("NYASH_JOINIR_VM_BRIDGE")
|
||||
.ok()
|
||||
.as_deref()
|
||||
!= Some("1")
|
||||
{
|
||||
eprintln!(
|
||||
"[joinir/vm_bridge] NYASH_JOINIR_VM_BRIDGE=1 not set, skipping VM bridge test"
|
||||
);
|
||||
if std::env::var("NYASH_JOINIR_VM_BRIDGE").ok().as_deref() != Some("1") {
|
||||
eprintln!("[joinir/vm_bridge] NYASH_JOINIR_VM_BRIDGE=1 not set, skipping VM bridge test");
|
||||
return false;
|
||||
}
|
||||
true
|
||||
@ -57,8 +51,7 @@ static box Runner {
|
||||
"#;
|
||||
let full_src = format!("{src}\n{runner}");
|
||||
|
||||
let ast: ASTNode =
|
||||
NyashParser::parse_from_string(&full_src).expect("skip_ws: parse failed");
|
||||
let ast: ASTNode = NyashParser::parse_from_string(&full_src).expect("skip_ws: parse failed");
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let compiled = mc.compile(ast).expect("skip_ws: MIR compile failed");
|
||||
|
||||
@ -86,10 +79,16 @@ static box Runner {
|
||||
)
|
||||
.expect("JoinIR VM bridge failed for skip_ws");
|
||||
|
||||
eprintln!("[joinir_vm_bridge_test] Route C result: {:?}", bridge_result);
|
||||
eprintln!(
|
||||
"[joinir_vm_bridge_test] Route C result: {:?}",
|
||||
bridge_result
|
||||
);
|
||||
|
||||
// Assertions: Both routes should produce the same result
|
||||
assert_eq!(vm_result, "3", "Route A (VM) expected to skip 3 leading spaces");
|
||||
assert_eq!(
|
||||
vm_result, "3",
|
||||
"Route A (VM) expected to skip 3 leading spaces"
|
||||
);
|
||||
match bridge_result {
|
||||
JoinValue::Int(v) => {
|
||||
assert_eq!(v, 3, "Route C (JoinIR→VM bridge) skip_ws result mismatch");
|
||||
|
||||
@ -106,4 +106,3 @@ static box Main {
|
||||
std::env::remove_var("NYASH_DISABLE_PLUGINS");
|
||||
std::env::remove_var("HAKO_MIR_BUILDER_METHODIZE");
|
||||
}
|
||||
|
||||
|
||||
@ -30,10 +30,8 @@ fn mir_funcscanner_parse_params_trim_min_verify_and_vm() {
|
||||
// std::env::set_var("NYASH_IF_HOLE_TRACE", "1");
|
||||
|
||||
// Bundle FuncScanner 本体と最小テスト。
|
||||
let func_scanner_src =
|
||||
include_str!("../../lang/src/compiler/entry/func_scanner.hako");
|
||||
let test_src =
|
||||
std::fs::read_to_string(test_file).expect("Failed to read minimal test .hako");
|
||||
let func_scanner_src = include_str!("../../lang/src/compiler/entry/func_scanner.hako");
|
||||
let test_src = std::fs::read_to_string(test_file).expect("Failed to read minimal test .hako");
|
||||
let src = format!("{func_scanner_src}\n\n{test_src}");
|
||||
|
||||
let ast: ASTNode =
|
||||
@ -86,4 +84,3 @@ fn mir_funcscanner_parse_params_trim_min_verify_and_vm() {
|
||||
std::env::remove_var("NYASH_VM_VERIFY_MIR");
|
||||
std::env::remove_var("NYASH_IF_HOLE_TRACE");
|
||||
}
|
||||
|
||||
|
||||
@ -29,14 +29,11 @@ fn mir_funcscanner_trim_min_verify_and_vm() {
|
||||
// std::env::set_var("NYASH_IF_HOLE_TRACE", "1");
|
||||
|
||||
// FuncScanner 本体と最小 _trim テストを 1 ソースにまとめる。
|
||||
let func_scanner_src =
|
||||
include_str!("../../lang/src/compiler/entry/func_scanner.hako");
|
||||
let test_src =
|
||||
std::fs::read_to_string(test_file).expect("Failed to read trim_min .hako");
|
||||
let func_scanner_src = include_str!("../../lang/src/compiler/entry/func_scanner.hako");
|
||||
let test_src = std::fs::read_to_string(test_file).expect("Failed to read trim_min .hako");
|
||||
let src = format!("{func_scanner_src}\n\n{test_src}");
|
||||
|
||||
let ast: ASTNode =
|
||||
NyashParser::parse_from_string(&src).expect("trim_min: parse failed");
|
||||
let ast: ASTNode = NyashParser::parse_from_string(&src).expect("trim_min: parse failed");
|
||||
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let compiled = mc.compile(ast).expect("trim_min: MIR compile failed");
|
||||
|
||||
@ -25,6 +25,7 @@ use crate::mir::join_ir::lowering::funcscanner_append_defs::lower_funcscanner_ap
|
||||
use crate::mir::join_ir::*;
|
||||
use crate::mir::{MirCompiler, ValueId};
|
||||
use crate::parser::NyashParser;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[test]
|
||||
#[ignore] // 手動実行用(Phase 27.14 実験段階)
|
||||
@ -47,11 +48,13 @@ fn mir_joinir_funcscanner_append_defs_auto_lowering() {
|
||||
let src = std::fs::read_to_string(test_file)
|
||||
.unwrap_or_else(|_| panic!("Failed to read {}", test_file));
|
||||
|
||||
let ast: ASTNode = NyashParser::parse_from_string(&src)
|
||||
.expect("funcscanner_append_defs: parse failed");
|
||||
let ast: ASTNode =
|
||||
NyashParser::parse_from_string(&src).expect("funcscanner_append_defs: parse failed");
|
||||
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let compiled = mc.compile(ast).expect("funcscanner_append_defs: MIR compile failed");
|
||||
let compiled = mc
|
||||
.compile(ast)
|
||||
.expect("funcscanner_append_defs: MIR compile failed");
|
||||
|
||||
eprintln!(
|
||||
"[joinir/funcscanner_append_defs] MIR module compiled, {} functions",
|
||||
@ -66,32 +69,69 @@ fn mir_joinir_funcscanner_append_defs_auto_lowering() {
|
||||
eprintln!("{:#?}", join_module);
|
||||
|
||||
// Step 3: 妥当性検証(Phase 27.14)
|
||||
assert_eq!(join_module.functions.len(), 2, "Expected 2 functions (append_defs_entry + loop_step)");
|
||||
assert_eq!(
|
||||
join_module.functions.len(),
|
||||
2,
|
||||
"Expected 2 functions (append_defs_entry + loop_step)"
|
||||
);
|
||||
|
||||
let entry_id = JoinFuncId::new(0);
|
||||
let loop_step_id = JoinFuncId::new(1);
|
||||
|
||||
// append_defs_entry 関数の検証
|
||||
let entry_func = join_module.functions.get(&entry_id)
|
||||
let entry_func = join_module
|
||||
.functions
|
||||
.get(&entry_id)
|
||||
.expect("append_defs_entry function not found");
|
||||
assert_eq!(entry_func.name, "append_defs_entry");
|
||||
assert_eq!(entry_func.params.len(), 3, "append_defs_entry has 3 parameters (dst, defs_box, n)");
|
||||
assert_eq!(
|
||||
entry_func.params.len(),
|
||||
3,
|
||||
"append_defs_entry has 3 parameters (dst, defs_box, n)"
|
||||
);
|
||||
|
||||
// loop_step 関数の検証
|
||||
let loop_step_func = join_module.functions.get(&loop_step_id)
|
||||
let loop_step_func = join_module
|
||||
.functions
|
||||
.get(&loop_step_id)
|
||||
.expect("loop_step function not found");
|
||||
assert_eq!(loop_step_func.name, "loop_step");
|
||||
assert_eq!(loop_step_func.params.len(), 4, "loop_step has 4 parameters (dst, defs_box, n, i)");
|
||||
assert_eq!(
|
||||
loop_step_func.params.len(),
|
||||
4,
|
||||
"loop_step has 4 parameters (dst, defs_box, n, i)"
|
||||
);
|
||||
|
||||
// ValueId range 検証 (9000-10999)
|
||||
assert_eq!(entry_func.params[0].0, 9000, "dst parameter should be ValueId(9000)");
|
||||
assert_eq!(entry_func.params[1].0, 9001, "defs_box parameter should be ValueId(9001)");
|
||||
assert_eq!(entry_func.params[2].0, 9002, "n parameter should be ValueId(9002)");
|
||||
assert_eq!(
|
||||
entry_func.params[0].0, 9000,
|
||||
"dst parameter should be ValueId(9000)"
|
||||
);
|
||||
assert_eq!(
|
||||
entry_func.params[1].0, 9001,
|
||||
"defs_box parameter should be ValueId(9001)"
|
||||
);
|
||||
assert_eq!(
|
||||
entry_func.params[2].0, 9002,
|
||||
"n parameter should be ValueId(9002)"
|
||||
);
|
||||
|
||||
assert_eq!(loop_step_func.params[0].0, 10000, "dst_loop parameter should be ValueId(10000)");
|
||||
assert_eq!(loop_step_func.params[1].0, 10001, "defs_box_loop parameter should be ValueId(10001)");
|
||||
assert_eq!(loop_step_func.params[2].0, 10002, "n_loop parameter should be ValueId(10002)");
|
||||
assert_eq!(loop_step_func.params[3].0, 10003, "i_loop parameter should be ValueId(10003)");
|
||||
assert_eq!(
|
||||
loop_step_func.params[0].0, 10000,
|
||||
"dst_loop parameter should be ValueId(10000)"
|
||||
);
|
||||
assert_eq!(
|
||||
loop_step_func.params[1].0, 10001,
|
||||
"defs_box_loop parameter should be ValueId(10001)"
|
||||
);
|
||||
assert_eq!(
|
||||
loop_step_func.params[2].0, 10002,
|
||||
"n_loop parameter should be ValueId(10002)"
|
||||
);
|
||||
assert_eq!(
|
||||
loop_step_func.params[3].0, 10003,
|
||||
"i_loop parameter should be ValueId(10003)"
|
||||
);
|
||||
|
||||
eprintln!("[joinir/funcscanner_append_defs] ✅ 自動変換成功(Phase 27.14)");
|
||||
}
|
||||
@ -127,5 +167,78 @@ fn mir_joinir_funcscanner_append_defs_empty_module_returns_none() {
|
||||
let result = lower_funcscanner_append_defs_to_joinir(&test_module);
|
||||
|
||||
eprintln!("[joinir/funcscanner_append_defs] empty_module test: result is None (expected)");
|
||||
assert!(result.is_none(), "Empty MirModule should return None (target function not found)");
|
||||
assert!(
|
||||
result.is_none(),
|
||||
"Empty MirModule should return None (target function not found)"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // 手動実行: generic_case_a トグル検証(append_defs minimal)
|
||||
fn mir_joinir_funcscanner_append_defs_generic_matches_handwritten() {
|
||||
if std::env::var("NYASH_JOINIR_EXPERIMENT").ok().as_deref() != Some("1") {
|
||||
eprintln!("[joinir/funcscanner_append_defs] NYASH_JOINIR_EXPERIMENT=1 not set, skipping generic test");
|
||||
return;
|
||||
}
|
||||
|
||||
std::env::set_var("NYASH_PARSER_STAGE3", "1");
|
||||
std::env::set_var("HAKO_PARSER_STAGE3", "1");
|
||||
|
||||
let test_file = "apps/tests/funcscanner_append_defs_minimal.hako";
|
||||
let src = std::fs::read_to_string(test_file)
|
||||
.unwrap_or_else(|_| panic!("Failed to read {}", test_file));
|
||||
|
||||
let ast: ASTNode =
|
||||
NyashParser::parse_from_string(&src).expect("append_defs generic: parse failed");
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let compiled = mc
|
||||
.compile(ast)
|
||||
.expect("append_defs generic: MIR compile failed");
|
||||
|
||||
fn params_by_name(jm: &JoinModule) -> BTreeMap<String, usize> {
|
||||
jm.functions
|
||||
.values()
|
||||
.map(|f| (f.name.clone(), f.params.len()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
// Baseline (generic OFF)
|
||||
std::env::set_var("NYASH_JOINIR_LOWER_GENERIC", "0");
|
||||
let baseline = lower_funcscanner_append_defs_to_joinir(&compiled.module)
|
||||
.expect("baseline append_defs lowering failed");
|
||||
|
||||
// Generic ON
|
||||
std::env::set_var("NYASH_JOINIR_LOWER_GENERIC", "1");
|
||||
let generic = lower_funcscanner_append_defs_to_joinir(&compiled.module)
|
||||
.expect("generic append_defs lowering failed");
|
||||
|
||||
let baseline_params = params_by_name(&baseline);
|
||||
let generic_params = params_by_name(&generic);
|
||||
|
||||
assert_eq!(baseline_params.len(), 2, "baseline should have 2 functions");
|
||||
assert_eq!(generic_params.len(), 2, "generic should have 2 functions");
|
||||
assert_eq!(
|
||||
baseline_params.len(),
|
||||
generic_params.len(),
|
||||
"function count mismatch"
|
||||
);
|
||||
|
||||
let expected_funcs = ["append_defs_entry", "loop_step"];
|
||||
for name in expected_funcs {
|
||||
let b_params = baseline_params
|
||||
.get(name)
|
||||
.copied()
|
||||
.unwrap_or_else(|| panic!("baseline missing function {}", name));
|
||||
let g_params = generic_params
|
||||
.get(name)
|
||||
.copied()
|
||||
.unwrap_or_else(|| panic!("generic missing function {}", name));
|
||||
assert_eq!(
|
||||
b_params, g_params,
|
||||
"param count differs for function {}",
|
||||
name
|
||||
);
|
||||
}
|
||||
|
||||
eprintln!("[joinir/funcscanner_append_defs] ✅ generic_case_a JoinIR matches baseline");
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@ use crate::ast::ASTNode;
|
||||
use crate::mir::join_ir::*;
|
||||
use crate::mir::{MirCompiler, ValueId};
|
||||
use crate::parser::NyashParser;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[test]
|
||||
#[ignore] // 手動実行用(Phase 27.1 実験段階)
|
||||
@ -51,8 +52,7 @@ fn mir_joinir_funcscanner_trim_auto_lowering() {
|
||||
.unwrap_or_else(|_| panic!("Failed to read {}", test_file));
|
||||
let src = format!("{func_scanner_src}\n\n{test_src}");
|
||||
|
||||
let ast: ASTNode = NyashParser::parse_from_string(&src)
|
||||
.expect("trim: parse failed");
|
||||
let ast: ASTNode = NyashParser::parse_from_string(&src).expect("trim: parse failed");
|
||||
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let compiled = mc.compile(ast).expect("trim: MIR compile failed");
|
||||
@ -70,24 +70,46 @@ fn mir_joinir_funcscanner_trim_auto_lowering() {
|
||||
eprintln!("{:#?}", join_module);
|
||||
|
||||
// Step 3: 妥当性検証
|
||||
assert_eq!(join_module.functions.len(), 3, "Expected 3 functions (trim_main + loop_step + skip_leading)");
|
||||
assert_eq!(
|
||||
join_module.functions.len(),
|
||||
3,
|
||||
"Expected 3 functions (trim_main + loop_step + skip_leading)"
|
||||
);
|
||||
|
||||
let trim_main_id = JoinFuncId::new(0);
|
||||
let loop_step_id = JoinFuncId::new(1);
|
||||
|
||||
// trim_main 関数の検証
|
||||
let trim_main_func = join_module.functions.get(&trim_main_id)
|
||||
let trim_main_func = join_module
|
||||
.functions
|
||||
.get(&trim_main_id)
|
||||
.expect("trim_main function not found");
|
||||
assert_eq!(trim_main_func.name, "trim_main");
|
||||
assert_eq!(trim_main_func.params.len(), 1, "trim_main has 1 parameter (s)");
|
||||
assert!(trim_main_func.body.len() >= 5, "trim_main should have at least 5 instructions");
|
||||
assert_eq!(
|
||||
trim_main_func.params.len(),
|
||||
1,
|
||||
"trim_main has 1 parameter (s)"
|
||||
);
|
||||
assert!(
|
||||
trim_main_func.body.len() >= 5,
|
||||
"trim_main should have at least 5 instructions"
|
||||
);
|
||||
|
||||
// loop_step 関数の検証
|
||||
let loop_step_func = join_module.functions.get(&loop_step_id)
|
||||
let loop_step_func = join_module
|
||||
.functions
|
||||
.get(&loop_step_id)
|
||||
.expect("loop_step function not found");
|
||||
assert_eq!(loop_step_func.name, "loop_step");
|
||||
assert_eq!(loop_step_func.params.len(), 3, "loop_step has 3 parameters (str, b, e)");
|
||||
assert!(loop_step_func.body.len() >= 10, "loop_step should have multiple instructions");
|
||||
assert_eq!(
|
||||
loop_step_func.params.len(),
|
||||
3,
|
||||
"loop_step has 3 parameters (str, b, e)"
|
||||
);
|
||||
assert!(
|
||||
loop_step_func.body.len() >= 10,
|
||||
"loop_step should have multiple instructions"
|
||||
);
|
||||
|
||||
eprintln!("[joinir/trim] ✅ 自動変換成功(Phase 27.1)");
|
||||
}
|
||||
@ -98,14 +120,82 @@ fn mir_joinir_funcscanner_trim_type_sanity() {
|
||||
// trim 用の JoinFunction が作成できることを確認
|
||||
|
||||
let trim_main_id = JoinFuncId::new(10);
|
||||
let trim_main_func = JoinFunction::new(
|
||||
trim_main_id,
|
||||
"trim_main_test".to_string(),
|
||||
vec![ValueId(1)],
|
||||
);
|
||||
let trim_main_func =
|
||||
JoinFunction::new(trim_main_id, "trim_main_test".to_string(), vec![ValueId(1)]);
|
||||
|
||||
assert_eq!(trim_main_func.id, trim_main_id);
|
||||
assert_eq!(trim_main_func.name, "trim_main_test");
|
||||
assert_eq!(trim_main_func.params.len(), 1);
|
||||
assert_eq!(trim_main_func.body.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // 手動実行: generic_case_a トグル検証(trim minimal)
|
||||
fn mir_joinir_funcscanner_trim_generic_matches_handwritten() {
|
||||
if std::env::var("NYASH_JOINIR_EXPERIMENT").ok().as_deref() != Some("1") {
|
||||
eprintln!("[joinir/trim] NYASH_JOINIR_EXPERIMENT=1 not set, skipping generic test");
|
||||
return;
|
||||
}
|
||||
|
||||
std::env::set_var("NYASH_PARSER_STAGE3", "1");
|
||||
std::env::set_var("HAKO_PARSER_STAGE3", "1");
|
||||
std::env::set_var("NYASH_ENABLE_USING", "1");
|
||||
std::env::set_var("HAKO_ENABLE_USING", "1");
|
||||
|
||||
let func_scanner_src = include_str!("../../lang/src/compiler/entry/func_scanner.hako");
|
||||
let test_file = "lang/src/compiler/tests/funcscanner_trim_min.hako";
|
||||
let test_src = std::fs::read_to_string(test_file)
|
||||
.unwrap_or_else(|_| panic!("Failed to read {}", test_file));
|
||||
let src = format!("{func_scanner_src}\n\n{test_src}");
|
||||
|
||||
let ast: ASTNode = NyashParser::parse_from_string(&src).expect("trim generic: parse failed");
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let compiled = mc.compile(ast).expect("trim generic: MIR compile failed");
|
||||
|
||||
fn params_by_name(jm: &JoinModule) -> BTreeMap<String, usize> {
|
||||
jm.functions
|
||||
.values()
|
||||
.map(|f| (f.name.clone(), f.params.len()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
// Baseline (generic OFF)
|
||||
std::env::set_var("NYASH_JOINIR_LOWER_GENERIC", "0");
|
||||
let baseline =
|
||||
lower_funcscanner_trim_to_joinir(&compiled.module).expect("baseline trim lowering failed");
|
||||
|
||||
// Generic ON
|
||||
std::env::set_var("NYASH_JOINIR_LOWER_GENERIC", "1");
|
||||
let generic =
|
||||
lower_funcscanner_trim_to_joinir(&compiled.module).expect("generic trim lowering failed");
|
||||
|
||||
let baseline_params = params_by_name(&baseline);
|
||||
let generic_params = params_by_name(&generic);
|
||||
|
||||
assert_eq!(baseline_params.len(), 3, "baseline should have 3 functions");
|
||||
assert_eq!(generic_params.len(), 3, "generic should have 3 functions");
|
||||
assert_eq!(
|
||||
baseline_params.len(),
|
||||
generic_params.len(),
|
||||
"function count mismatch"
|
||||
);
|
||||
|
||||
let expected_funcs = ["trim_main", "loop_step", "skip_leading"];
|
||||
for name in expected_funcs {
|
||||
let b_params = baseline_params
|
||||
.get(name)
|
||||
.copied()
|
||||
.unwrap_or_else(|| panic!("baseline missing function {}", name));
|
||||
let g_params = generic_params
|
||||
.get(name)
|
||||
.copied()
|
||||
.unwrap_or_else(|| panic!("generic missing function {}", name));
|
||||
assert_eq!(
|
||||
b_params, g_params,
|
||||
"param count differs for function {}",
|
||||
name
|
||||
);
|
||||
}
|
||||
|
||||
eprintln!("[joinir/trim] ✅ generic_case_a JoinIR matches baseline");
|
||||
}
|
||||
|
||||
@ -23,7 +23,9 @@ fn mir_joinir_min_manual_construction() {
|
||||
|
||||
// 環境変数トグルチェック
|
||||
if std::env::var("NYASH_JOINIR_EXPERIMENT").ok().as_deref() != Some("1") {
|
||||
eprintln!("[joinir/min] NYASH_JOINIR_EXPERIMENT=1 not set, skipping manual construction test");
|
||||
eprintln!(
|
||||
"[joinir/min] NYASH_JOINIR_EXPERIMENT=1 not set, skipping manual construction test"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -36,8 +38,7 @@ fn mir_joinir_min_manual_construction() {
|
||||
let src = std::fs::read_to_string(test_file)
|
||||
.unwrap_or_else(|_| panic!("Failed to read {}", test_file));
|
||||
|
||||
let ast: ASTNode = NyashParser::parse_from_string(&src)
|
||||
.expect("joinir_min: parse failed");
|
||||
let ast: ASTNode = NyashParser::parse_from_string(&src).expect("joinir_min: parse failed");
|
||||
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let compiled = mc.compile(ast).expect("joinir_min: MIR compile failed");
|
||||
@ -85,18 +86,22 @@ fn mir_joinir_min_manual_construction() {
|
||||
let i_plus_1 = ValueId(202);
|
||||
|
||||
// cmp_result = (i >= 2)
|
||||
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Compare {
|
||||
dst: cmp_result,
|
||||
op: CompareOp::Ge,
|
||||
lhs: i_param,
|
||||
rhs: ValueId(203), // const 2
|
||||
}));
|
||||
loop_step_func
|
||||
.body
|
||||
.push(JoinInst::Compute(MirLikeInst::Compare {
|
||||
dst: cmp_result,
|
||||
op: CompareOp::Ge,
|
||||
lhs: i_param,
|
||||
rhs: ValueId(203), // const 2
|
||||
}));
|
||||
|
||||
// const 2
|
||||
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: ValueId(203),
|
||||
value: ConstValue::Integer(2),
|
||||
}));
|
||||
loop_step_func
|
||||
.body
|
||||
.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: ValueId(203),
|
||||
value: ConstValue::Integer(2),
|
||||
}));
|
||||
|
||||
// if cmp_result { k_exit(i) } else { loop_step(i+1, k_exit) }
|
||||
// ここでは簡略化して Jump 命令だけ書く(実際は分岐制御が必要だが Phase 26-H では型チェックのみ)
|
||||
@ -107,12 +112,14 @@ fn mir_joinir_min_manual_construction() {
|
||||
});
|
||||
|
||||
// i_plus_1 = i + 1
|
||||
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::BinOp {
|
||||
dst: i_plus_1,
|
||||
op: BinOpKind::Add,
|
||||
lhs: i_param,
|
||||
rhs: ValueId(204), // const 1
|
||||
}));
|
||||
loop_step_func
|
||||
.body
|
||||
.push(JoinInst::Compute(MirLikeInst::BinOp {
|
||||
dst: i_plus_1,
|
||||
op: BinOpKind::Add,
|
||||
lhs: i_param,
|
||||
rhs: ValueId(204), // const 1
|
||||
}));
|
||||
|
||||
join_module.add_function(loop_step_func);
|
||||
|
||||
@ -148,8 +155,7 @@ fn mir_joinir_min_auto_lowering() {
|
||||
let src = std::fs::read_to_string(test_file)
|
||||
.unwrap_or_else(|_| panic!("Failed to read {}", test_file));
|
||||
|
||||
let ast: ASTNode = NyashParser::parse_from_string(&src)
|
||||
.expect("joinir_min: parse failed");
|
||||
let ast: ASTNode = NyashParser::parse_from_string(&src).expect("joinir_min: parse failed");
|
||||
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let compiled = mc.compile(ast).expect("joinir_min: MIR compile failed");
|
||||
@ -160,31 +166,49 @@ fn mir_joinir_min_auto_lowering() {
|
||||
);
|
||||
|
||||
// Step 2: MIR → JoinIR 自動変換
|
||||
let join_module = lower_min_loop_to_joinir(&compiled.module)
|
||||
.expect("lower_min_loop_to_joinir failed");
|
||||
let join_module =
|
||||
lower_min_loop_to_joinir(&compiled.module).expect("lower_min_loop_to_joinir failed");
|
||||
|
||||
eprintln!("[joinir/auto] JoinIR module generated:");
|
||||
eprintln!("{:#?}", join_module);
|
||||
|
||||
// Step 3: 妥当性検証
|
||||
assert_eq!(join_module.functions.len(), 2, "Expected 2 functions (main + loop_step)");
|
||||
assert_eq!(
|
||||
join_module.functions.len(),
|
||||
2,
|
||||
"Expected 2 functions (main + loop_step)"
|
||||
);
|
||||
|
||||
let main_id = JoinFuncId::new(0);
|
||||
let loop_step_id = JoinFuncId::new(1);
|
||||
|
||||
// main 関数の検証
|
||||
let main_func = join_module.functions.get(&main_id)
|
||||
let main_func = join_module
|
||||
.functions
|
||||
.get(&main_id)
|
||||
.expect("main function not found");
|
||||
assert_eq!(main_func.name, "main");
|
||||
assert_eq!(main_func.params.len(), 0, "main has no parameters");
|
||||
assert!(main_func.body.len() >= 2, "main should have at least 2 instructions (const + call)");
|
||||
assert!(
|
||||
main_func.body.len() >= 2,
|
||||
"main should have at least 2 instructions (const + call)"
|
||||
);
|
||||
|
||||
// loop_step 関数の検証
|
||||
let loop_step_func = join_module.functions.get(&loop_step_id)
|
||||
let loop_step_func = join_module
|
||||
.functions
|
||||
.get(&loop_step_id)
|
||||
.expect("loop_step function not found");
|
||||
assert_eq!(loop_step_func.name, "loop_step");
|
||||
assert_eq!(loop_step_func.params.len(), 1, "loop_step has 1 parameter (i)");
|
||||
assert!(loop_step_func.body.len() >= 4, "loop_step should have multiple instructions");
|
||||
assert_eq!(
|
||||
loop_step_func.params.len(),
|
||||
1,
|
||||
"loop_step has 1 parameter (i)"
|
||||
);
|
||||
assert!(
|
||||
loop_step_func.body.len() >= 4,
|
||||
"loop_step should have multiple instructions"
|
||||
);
|
||||
|
||||
eprintln!("[joinir/auto] ✅ 自動変換成功(Phase 26-H Step 2)");
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@ use crate::ast::ASTNode;
|
||||
use crate::mir::join_ir::*;
|
||||
use crate::mir::{MirCompiler, ValueId};
|
||||
use crate::parser::NyashParser;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[test]
|
||||
#[ignore] // 手動実行用(Phase 27.1 実験段階)
|
||||
@ -32,7 +33,9 @@ fn mir_joinir_skip_ws_auto_lowering() {
|
||||
|
||||
// 環境変数トグルチェック
|
||||
if std::env::var("NYASH_JOINIR_EXPERIMENT").ok().as_deref() != Some("1") {
|
||||
eprintln!("[joinir/skip_ws] NYASH_JOINIR_EXPERIMENT=1 not set, skipping auto-lowering test");
|
||||
eprintln!(
|
||||
"[joinir/skip_ws] NYASH_JOINIR_EXPERIMENT=1 not set, skipping auto-lowering test"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -45,8 +48,7 @@ fn mir_joinir_skip_ws_auto_lowering() {
|
||||
let src = std::fs::read_to_string(test_file)
|
||||
.unwrap_or_else(|_| panic!("Failed to read {}", test_file));
|
||||
|
||||
let ast: ASTNode = NyashParser::parse_from_string(&src)
|
||||
.expect("skip_ws: parse failed");
|
||||
let ast: ASTNode = NyashParser::parse_from_string(&src).expect("skip_ws: parse failed");
|
||||
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let compiled = mc.compile(ast).expect("skip_ws: MIR compile failed");
|
||||
@ -57,30 +59,45 @@ fn mir_joinir_skip_ws_auto_lowering() {
|
||||
);
|
||||
|
||||
// Step 2: MIR → JoinIR 自動変換
|
||||
let join_module = lower_skip_ws_to_joinir(&compiled.module)
|
||||
.expect("lower_skip_ws_to_joinir failed");
|
||||
let join_module =
|
||||
lower_skip_ws_to_joinir(&compiled.module).expect("lower_skip_ws_to_joinir failed");
|
||||
|
||||
eprintln!("[joinir/skip_ws] JoinIR module generated:");
|
||||
eprintln!("{:#?}", join_module);
|
||||
|
||||
// Step 3: 妥当性検証
|
||||
assert_eq!(join_module.functions.len(), 2, "Expected 2 functions (skip + loop_step)");
|
||||
assert_eq!(
|
||||
join_module.functions.len(),
|
||||
2,
|
||||
"Expected 2 functions (skip + loop_step)"
|
||||
);
|
||||
|
||||
let skip_id = JoinFuncId::new(0);
|
||||
let loop_step_id = JoinFuncId::new(1);
|
||||
|
||||
// skip 関数の検証
|
||||
let skip_func = join_module.functions.get(&skip_id)
|
||||
let skip_func = join_module
|
||||
.functions
|
||||
.get(&skip_id)
|
||||
.expect("skip function not found");
|
||||
assert_eq!(skip_func.name, "skip");
|
||||
assert_eq!(skip_func.params.len(), 1, "skip has 1 parameter (s)");
|
||||
assert!(skip_func.body.len() >= 3, "skip should have at least 3 instructions (const 0, length call, loop_step call)");
|
||||
assert!(
|
||||
skip_func.body.len() >= 3,
|
||||
"skip should have at least 3 instructions (const 0, length call, loop_step call)"
|
||||
);
|
||||
|
||||
// loop_step 関数の検証
|
||||
let loop_step_func = join_module.functions.get(&loop_step_id)
|
||||
let loop_step_func = join_module
|
||||
.functions
|
||||
.get(&loop_step_id)
|
||||
.expect("loop_step function not found");
|
||||
assert_eq!(loop_step_func.name, "loop_step");
|
||||
assert_eq!(loop_step_func.params.len(), 3, "loop_step has 3 parameters (s, i, n)");
|
||||
assert_eq!(
|
||||
loop_step_func.params.len(),
|
||||
3,
|
||||
"loop_step has 3 parameters (s, i, n)"
|
||||
);
|
||||
assert!(loop_step_func.body.len() >= 8, "loop_step should have multiple instructions (comparisons, substring, recursive call, etc.)");
|
||||
|
||||
eprintln!("[joinir/skip_ws] ✅ 自動変換成功(Phase 27.1)");
|
||||
@ -103,3 +120,97 @@ fn mir_joinir_skip_ws_type_sanity() {
|
||||
assert_eq!(skip_func.params.len(), 3);
|
||||
assert_eq!(skip_func.body.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mir_joinir_skip_ws_generic_matches_handwritten() {
|
||||
if std::env::var("NYASH_JOINIR_EXPERIMENT").ok().as_deref() != Some("1") {
|
||||
eprintln!("[joinir/skip_ws] NYASH_JOINIR_EXPERIMENT=1 not set, skipping generic test");
|
||||
return;
|
||||
}
|
||||
|
||||
// Stage-3 parserを有効化
|
||||
std::env::set_var("NYASH_PARSER_STAGE3", "1");
|
||||
std::env::set_var("HAKO_PARSER_STAGE3", "1");
|
||||
|
||||
let test_file = "apps/tests/minimal_ssa_skip_ws.hako";
|
||||
let src = std::fs::read_to_string(test_file)
|
||||
.unwrap_or_else(|_| panic!("Failed to read {}", test_file));
|
||||
|
||||
let ast: ASTNode = NyashParser::parse_from_string(&src).expect("skip_ws generic: parse failed");
|
||||
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let compiled = mc
|
||||
.compile(ast)
|
||||
.expect("skip_ws generic: MIR compile failed");
|
||||
|
||||
fn params_by_name(jm: &JoinModule) -> BTreeMap<String, usize> {
|
||||
jm.functions
|
||||
.values()
|
||||
.map(|f| (f.name.clone(), f.params.len()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn has_jump_to_cont(jm: &JoinModule, func_name: &str, cont: JoinContId) -> bool {
|
||||
jm.functions
|
||||
.values()
|
||||
.find(|f| f.name == func_name)
|
||||
.map(|f| {
|
||||
f.body.iter().any(|inst| match inst {
|
||||
JoinInst::Jump { cont: c, .. } => *c == cont,
|
||||
_ => false,
|
||||
})
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
// Baseline (generic OFF)
|
||||
std::env::set_var("NYASH_JOINIR_LOWER_GENERIC", "0");
|
||||
let baseline =
|
||||
lower_skip_ws_to_joinir(&compiled.module).expect("baseline skip_ws lowering failed");
|
||||
|
||||
// Generic ON
|
||||
std::env::set_var("NYASH_JOINIR_LOWER_GENERIC", "1");
|
||||
let generic =
|
||||
lower_skip_ws_to_joinir(&compiled.module).expect("generic skip_ws lowering failed");
|
||||
|
||||
// Compare shape (function count + params + loop_step/k_exit 相当の存在確認)
|
||||
let baseline_params = params_by_name(&baseline);
|
||||
let generic_params = params_by_name(&generic);
|
||||
|
||||
assert_eq!(baseline_params.len(), 2, "baseline should have 2 functions");
|
||||
assert_eq!(generic_params.len(), 2, "generic should have 2 functions");
|
||||
assert_eq!(
|
||||
baseline_params.len(),
|
||||
generic_params.len(),
|
||||
"function count mismatch"
|
||||
);
|
||||
|
||||
let expected_funcs = ["skip", "loop_step"];
|
||||
for name in expected_funcs {
|
||||
let b_params = baseline_params
|
||||
.get(name)
|
||||
.copied()
|
||||
.unwrap_or_else(|| panic!("baseline missing function {}", name));
|
||||
let g_params = generic_params
|
||||
.get(name)
|
||||
.copied()
|
||||
.unwrap_or_else(|| panic!("generic missing function {}", name));
|
||||
assert_eq!(
|
||||
b_params, g_params,
|
||||
"param count differs for function {}",
|
||||
name
|
||||
);
|
||||
}
|
||||
|
||||
let exit_cont = JoinContId::new(0);
|
||||
assert!(
|
||||
has_jump_to_cont(&baseline, "loop_step", exit_cont),
|
||||
"baseline loop_step should jump to k_exit(cont0)"
|
||||
);
|
||||
assert!(
|
||||
has_jump_to_cont(&generic, "loop_step", exit_cont),
|
||||
"generic loop_step should jump to k_exit(cont0)"
|
||||
);
|
||||
|
||||
eprintln!("[joinir/skip_ws] ✅ generic_case_a JoinIR matches baseline");
|
||||
}
|
||||
|
||||
@ -25,9 +25,10 @@ use crate::mir::join_ir::lowering::stage1_using_resolver::lower_stage1_usingreso
|
||||
use crate::mir::join_ir::*;
|
||||
use crate::mir::{MirCompiler, ValueId};
|
||||
use crate::parser::NyashParser;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[test]
|
||||
#[ignore] // 手動実行用(Phase 27.12 実験段階)
|
||||
#[ignore] // 手動実行用(Stage-1 minimal)
|
||||
fn mir_joinir_stage1_using_resolver_auto_lowering() {
|
||||
// Phase 27.12: Stage1UsingResolverBox.resolve_for_source の MIR → JoinIR 自動変換
|
||||
|
||||
@ -47,11 +48,13 @@ fn mir_joinir_stage1_using_resolver_auto_lowering() {
|
||||
let src = std::fs::read_to_string(test_file)
|
||||
.unwrap_or_else(|_| panic!("Failed to read {}", test_file));
|
||||
|
||||
let ast: ASTNode = NyashParser::parse_from_string(&src)
|
||||
.expect("stage1_using_resolver: parse failed");
|
||||
let ast: ASTNode =
|
||||
NyashParser::parse_from_string(&src).expect("stage1_using_resolver: parse failed");
|
||||
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let compiled = mc.compile(ast).expect("stage1_using_resolver: MIR compile failed");
|
||||
let compiled = mc
|
||||
.compile(ast)
|
||||
.expect("stage1_using_resolver: MIR compile failed");
|
||||
|
||||
eprintln!(
|
||||
"[joinir/stage1_using_resolver] MIR module compiled, {} functions",
|
||||
@ -66,22 +69,38 @@ fn mir_joinir_stage1_using_resolver_auto_lowering() {
|
||||
eprintln!("{:#?}", join_module);
|
||||
|
||||
// Step 3: 妥当性検証(Phase 27.13 以降で実装)
|
||||
assert_eq!(join_module.functions.len(), 2, "Expected 2 functions (resolve_entries + loop_step)");
|
||||
assert_eq!(
|
||||
join_module.functions.len(),
|
||||
2,
|
||||
"Expected 2 functions (resolve_entries + loop_step)"
|
||||
);
|
||||
|
||||
let resolve_id = JoinFuncId::new(0);
|
||||
let loop_step_id = JoinFuncId::new(1);
|
||||
|
||||
// resolve_entries 関数の検証
|
||||
let resolve_func = join_module.functions.get(&resolve_id)
|
||||
let resolve_func = join_module
|
||||
.functions
|
||||
.get(&resolve_id)
|
||||
.expect("resolve_entries function not found");
|
||||
assert_eq!(resolve_func.name, "resolve_entries");
|
||||
assert_eq!(resolve_func.params.len(), 5, "resolve_entries has 5 parameters (entries, n, modules, seen, prefix_init)");
|
||||
assert_eq!(
|
||||
resolve_func.params.len(),
|
||||
5,
|
||||
"resolve_entries has 5 parameters (entries, n, modules, seen, prefix_init)"
|
||||
);
|
||||
|
||||
// loop_step 関数の検証
|
||||
let loop_step_func = join_module.functions.get(&loop_step_id)
|
||||
let loop_step_func = join_module
|
||||
.functions
|
||||
.get(&loop_step_id)
|
||||
.expect("loop_step function not found");
|
||||
assert_eq!(loop_step_func.name, "loop_step");
|
||||
assert_eq!(loop_step_func.params.len(), 6, "loop_step has 6 parameters (entries, n, modules, seen, prefix, i)");
|
||||
assert_eq!(
|
||||
loop_step_func.params.len(),
|
||||
6,
|
||||
"loop_step has 6 parameters (entries, n, modules, seen, prefix, i)"
|
||||
);
|
||||
|
||||
eprintln!("[joinir/stage1_using_resolver] ✅ 自動変換成功(Phase 27.12/27.13)");
|
||||
}
|
||||
@ -117,5 +136,80 @@ fn mir_joinir_stage1_using_resolver_empty_module_returns_none() {
|
||||
let result = lower_stage1_usingresolver_to_joinir(&test_module);
|
||||
|
||||
eprintln!("[joinir/stage1_using_resolver] empty_module test: result is None (expected)");
|
||||
assert!(result.is_none(), "Empty MirModule should return None (target function not found)");
|
||||
assert!(
|
||||
result.is_none(),
|
||||
"Empty MirModule should return None (target function not found)"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // 手動実行: generic_case_a トグル検証(stage1_using_resolver minimal)
|
||||
fn mir_joinir_stage1_using_resolver_generic_matches_handwritten() {
|
||||
if std::env::var("NYASH_JOINIR_EXPERIMENT").ok().as_deref() != Some("1") {
|
||||
eprintln!(
|
||||
"[joinir/stage1_using_resolver] NYASH_JOINIR_EXPERIMENT=1 not set, skipping generic test"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
std::env::set_var("NYASH_PARSER_STAGE3", "1");
|
||||
std::env::set_var("HAKO_PARSER_STAGE3", "1");
|
||||
|
||||
let test_file = "apps/tests/stage1_usingresolver_minimal.hako";
|
||||
let src = std::fs::read_to_string(test_file)
|
||||
.unwrap_or_else(|_| panic!("Failed to read {}", test_file));
|
||||
|
||||
let ast: ASTNode =
|
||||
NyashParser::parse_from_string(&src).expect("stage1_using_resolver generic: parse failed");
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let compiled = mc
|
||||
.compile(ast)
|
||||
.expect("stage1_using_resolver generic: MIR compile failed");
|
||||
|
||||
fn params_by_name(jm: &JoinModule) -> BTreeMap<String, usize> {
|
||||
jm.functions
|
||||
.values()
|
||||
.map(|f| (f.name.clone(), f.params.len()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
// Baseline (generic OFF)
|
||||
std::env::set_var("NYASH_JOINIR_LOWER_GENERIC", "0");
|
||||
let baseline = lower_stage1_usingresolver_to_joinir(&compiled.module)
|
||||
.expect("baseline stage1_using_resolver lowering failed");
|
||||
|
||||
// Generic ON
|
||||
std::env::set_var("NYASH_JOINIR_LOWER_GENERIC", "1");
|
||||
let generic = lower_stage1_usingresolver_to_joinir(&compiled.module)
|
||||
.expect("generic stage1_using_resolver lowering failed");
|
||||
|
||||
let baseline_params = params_by_name(&baseline);
|
||||
let generic_params = params_by_name(&generic);
|
||||
|
||||
assert_eq!(baseline_params.len(), 2, "baseline should have 2 functions");
|
||||
assert_eq!(generic_params.len(), 2, "generic should have 2 functions");
|
||||
assert_eq!(
|
||||
baseline_params.len(),
|
||||
generic_params.len(),
|
||||
"function count mismatch"
|
||||
);
|
||||
|
||||
let expected_funcs = ["resolve_entries", "loop_step"];
|
||||
for name in expected_funcs {
|
||||
let b_params = baseline_params
|
||||
.get(name)
|
||||
.copied()
|
||||
.unwrap_or_else(|| panic!("baseline missing function {}", name));
|
||||
let g_params = generic_params
|
||||
.get(name)
|
||||
.copied()
|
||||
.unwrap_or_else(|| panic!("generic missing function {}", name));
|
||||
assert_eq!(
|
||||
b_params, g_params,
|
||||
"param count differs for function {}",
|
||||
name
|
||||
);
|
||||
}
|
||||
|
||||
eprintln!("[joinir/stage1_using_resolver] ✅ generic_case_a JoinIR matches baseline");
|
||||
}
|
||||
|
||||
101
src/tests/mir_joinir_stageb_body.rs
Normal file
101
src/tests/mir_joinir_stageb_body.rs
Normal file
@ -0,0 +1,101 @@
|
||||
// mir_joinir_stageb_body.rs
|
||||
// Phase 28: StageBBodyExtractorBox.build_body_src JoinIR 変換テスト
|
||||
//
|
||||
// 目的:
|
||||
// - StageBBodyExtractorBox.build_body_src/2 の Case A ループを JoinIR に落とせることを確認
|
||||
// - Pinned/Carrier/Exit の構造を固定化(Pinned: src/args/n, Carrier: acc/i, Exit: acc)
|
||||
//
|
||||
// 実行条件:
|
||||
// - #[ignore] で手動実行。環境変数 NYASH_JOINIR_EXPERIMENT=1 が必要。
|
||||
|
||||
use crate::ast::ASTNode;
|
||||
use crate::mir::join_ir::lowering::stageb_body::lower_stageb_body_to_joinir;
|
||||
use crate::mir::join_ir::*;
|
||||
use crate::mir::{MirCompiler, ValueId};
|
||||
use crate::parser::NyashParser;
|
||||
|
||||
#[test]
|
||||
#[ignore] // 手動実行用(実験モードのみ)
|
||||
fn mir_joinir_stageb_body_auto_lowering() {
|
||||
if std::env::var("NYASH_JOINIR_EXPERIMENT").ok().as_deref() != Some("1") {
|
||||
eprintln!(
|
||||
"[joinir/stageb_body] NYASH_JOINIR_EXPERIMENT=1 not set, skipping auto-lowering test"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Stage-3 パーサを有効化(local/loop を安全に扱うため)
|
||||
std::env::set_var("NYASH_PARSER_STAGE3", "1");
|
||||
std::env::set_var("HAKO_PARSER_STAGE3", "1");
|
||||
|
||||
let test_file = "apps/tests/stageb_body_extract_minimal.hako";
|
||||
let src = std::fs::read_to_string(test_file)
|
||||
.unwrap_or_else(|_| panic!("Failed to read {}", test_file));
|
||||
|
||||
let ast: ASTNode = NyashParser::parse_from_string(&src).expect("stageb_body: parse failed");
|
||||
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let compiled = mc.compile(ast).expect("stageb_body: MIR compile failed");
|
||||
|
||||
eprintln!(
|
||||
"[joinir/stageb_body] MIR module compiled, {} functions",
|
||||
compiled.module.functions.len()
|
||||
);
|
||||
|
||||
let join_module = lower_stageb_body_to_joinir(&compiled.module)
|
||||
.expect("StageBBodyExtractorBox.build_body_src should lower to JoinIR");
|
||||
|
||||
eprintln!("[joinir/stageb_body] JoinIR module generated:");
|
||||
eprintln!("{:#?}", join_module);
|
||||
|
||||
assert_eq!(join_module.functions.len(), 2, "Expected entry + loop_step");
|
||||
|
||||
let entry_id = JoinFuncId::new(0);
|
||||
let loop_id = JoinFuncId::new(1);
|
||||
|
||||
let entry_func = join_module
|
||||
.functions
|
||||
.get(&entry_id)
|
||||
.expect("build_body_src function not found");
|
||||
assert_eq!(entry_func.name, "build_body_src");
|
||||
assert_eq!(
|
||||
entry_func.params.len(),
|
||||
2,
|
||||
"build_body_src should take (src, args)"
|
||||
);
|
||||
|
||||
let loop_func = join_module
|
||||
.functions
|
||||
.get(&loop_id)
|
||||
.expect("loop_step function not found");
|
||||
assert_eq!(loop_func.name, "loop_step");
|
||||
assert_eq!(
|
||||
loop_func.params.len(),
|
||||
5,
|
||||
"loop_step should take (src, args, n, acc, i)"
|
||||
);
|
||||
|
||||
eprintln!("[joinir/stageb_body] ✅ 自動変換成功(Phase 28)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mir_joinir_stageb_body_type_sanity() {
|
||||
let entry_id = JoinFuncId::new(42);
|
||||
let f = JoinFunction::new(
|
||||
entry_id,
|
||||
"stageb_body_test".to_string(),
|
||||
vec![ValueId(1), ValueId(2)],
|
||||
);
|
||||
assert_eq!(f.id, entry_id);
|
||||
assert_eq!(f.name, "stageb_body_test");
|
||||
assert_eq!(f.params.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mir_joinir_stageb_body_empty_module_returns_none() {
|
||||
use crate::mir::MirModule;
|
||||
let test_module = MirModule::new("empty".to_string());
|
||||
let result = lower_stageb_body_to_joinir(&test_module);
|
||||
eprintln!("[joinir/stageb_body] empty_module test => {:?}", result);
|
||||
assert!(result.is_none());
|
||||
}
|
||||
105
src/tests/mir_joinir_stageb_funcscanner.rs
Normal file
105
src/tests/mir_joinir_stageb_funcscanner.rs
Normal file
@ -0,0 +1,105 @@
|
||||
// mir_joinir_stageb_funcscanner.rs
|
||||
// Phase 28: StageBFuncScannerBox.scan_all_boxes JoinIR 変換テスト
|
||||
//
|
||||
// 目的:
|
||||
// - StageBFuncScannerBox.scan_all_boxes/1 の Case A ループを JoinIR に落とせることを確認
|
||||
// - Pinned/Carrier/Exit の構造を固定化(Pinned: src/n, Carrier: defs/i, Exit: defs)
|
||||
//
|
||||
// 実行条件:
|
||||
// - #[ignore] で手動実行。環境変数 NYASH_JOINIR_EXPERIMENT=1 が必要。
|
||||
|
||||
use crate::ast::ASTNode;
|
||||
use crate::mir::join_ir::lowering::stageb_funcscanner::lower_stageb_funcscanner_to_joinir;
|
||||
use crate::mir::join_ir::*;
|
||||
use crate::mir::{MirCompiler, ValueId};
|
||||
use crate::parser::NyashParser;
|
||||
|
||||
#[test]
|
||||
#[ignore] // 手動実行用(実験モードのみ)
|
||||
fn mir_joinir_stageb_funcscanner_auto_lowering() {
|
||||
if std::env::var("NYASH_JOINIR_EXPERIMENT").ok().as_deref() != Some("1") {
|
||||
eprintln!("[joinir/stageb_funcscanner] NYASH_JOINIR_EXPERIMENT=1 not set, skipping auto-lowering test");
|
||||
return;
|
||||
}
|
||||
|
||||
// Stage-3 パーサを有効化
|
||||
std::env::set_var("NYASH_PARSER_STAGE3", "1");
|
||||
std::env::set_var("HAKO_PARSER_STAGE3", "1");
|
||||
|
||||
let test_file = "apps/tests/stageb_funcscanner_scan_boxes_minimal.hako";
|
||||
let src = std::fs::read_to_string(test_file)
|
||||
.unwrap_or_else(|_| panic!("Failed to read {}", test_file));
|
||||
|
||||
let ast: ASTNode =
|
||||
NyashParser::parse_from_string(&src).expect("stageb_funcscanner: parse failed");
|
||||
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let compiled = mc
|
||||
.compile(ast)
|
||||
.expect("stageb_funcscanner: MIR compile failed");
|
||||
|
||||
eprintln!(
|
||||
"[joinir/stageb_funcscanner] MIR module compiled, {} functions",
|
||||
compiled.module.functions.len()
|
||||
);
|
||||
|
||||
let join_module = lower_stageb_funcscanner_to_joinir(&compiled.module)
|
||||
.expect("StageBFuncScannerBox.scan_all_boxes should lower to JoinIR");
|
||||
|
||||
eprintln!("[joinir/stageb_funcscanner] JoinIR module generated:");
|
||||
eprintln!("{:#?}", join_module);
|
||||
|
||||
assert_eq!(join_module.functions.len(), 2, "Expected entry + loop_step");
|
||||
|
||||
let entry_id = JoinFuncId::new(0);
|
||||
let loop_id = JoinFuncId::new(1);
|
||||
|
||||
let entry_func = join_module
|
||||
.functions
|
||||
.get(&entry_id)
|
||||
.expect("scan_all_boxes function not found");
|
||||
assert_eq!(entry_func.name, "scan_all_boxes");
|
||||
assert_eq!(
|
||||
entry_func.params.len(),
|
||||
1,
|
||||
"scan_all_boxes should take (src)"
|
||||
);
|
||||
|
||||
let loop_func = join_module
|
||||
.functions
|
||||
.get(&loop_id)
|
||||
.expect("loop_step function not found");
|
||||
assert_eq!(loop_func.name, "loop_step");
|
||||
assert_eq!(
|
||||
loop_func.params.len(),
|
||||
4,
|
||||
"loop_step should take (src, n, defs, i)"
|
||||
);
|
||||
|
||||
eprintln!("[joinir/stageb_funcscanner] ✅ 自動変換成功(Phase 28)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mir_joinir_stageb_funcscanner_type_sanity() {
|
||||
let entry_id = JoinFuncId::new(24);
|
||||
let f = JoinFunction::new(
|
||||
entry_id,
|
||||
"stageb_funcscanner_test".to_string(),
|
||||
vec![ValueId(1)],
|
||||
);
|
||||
assert_eq!(f.id, entry_id);
|
||||
assert_eq!(f.name, "stageb_funcscanner_test");
|
||||
assert_eq!(f.params.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mir_joinir_stageb_funcscanner_empty_module_returns_none() {
|
||||
use crate::mir::MirModule;
|
||||
let test_module = MirModule::new("empty".to_string());
|
||||
let result = lower_stageb_funcscanner_to_joinir(&test_module);
|
||||
eprintln!(
|
||||
"[joinir/stageb_funcscanner] empty_module test => {:?}",
|
||||
result
|
||||
);
|
||||
assert!(result.is_none());
|
||||
}
|
||||
@ -82,4 +82,3 @@ fn mir_loopform_nested_region_verify() {
|
||||
}
|
||||
teardown_stage3_env();
|
||||
}
|
||||
|
||||
|
||||
@ -104,11 +104,7 @@ fn mir_stage1_cli_emit_program_min_exec_hits_type_error() {
|
||||
let cr = mc.compile(ast).expect("compile");
|
||||
|
||||
// Optional: scan for Compare::Ge instructions to locate suspicious comparisons
|
||||
if std::env::var("NYASH_STAGE1_SCAN_GE")
|
||||
.ok()
|
||||
.as_deref()
|
||||
== Some("1")
|
||||
{
|
||||
if std::env::var("NYASH_STAGE1_SCAN_GE").ok().as_deref() == Some("1") {
|
||||
for (fname, func) in cr.module.functions.iter() {
|
||||
for (bb_id, bb) in func.blocks.iter() {
|
||||
for inst in bb.instructions.iter() {
|
||||
|
||||
@ -40,8 +40,7 @@ fn ensure_stage3_env() {
|
||||
/// Stage‑1 CLI 全体を読み込まずに、StringHelpers 内部の `.length()` 正規化だけを確認する。
|
||||
fn stage1_staticcompiler_fixture_src() -> String {
|
||||
// StringHelpers 本体を直接バンドルして using 依存を排除。
|
||||
let string_helpers =
|
||||
include_str!("../../lang/src/shared/common/string_helpers.hako");
|
||||
let string_helpers = include_str!("../../lang/src/shared/common/string_helpers.hako");
|
||||
let test_main_src = r#"
|
||||
using lang.src.shared.common.string_helpers as StringHelpers
|
||||
|
||||
|
||||
@ -743,8 +743,6 @@ static box Stage1UsingResolverModulesMapContinueBreakLookup {
|
||||
for e in &errors {
|
||||
eprintln!("[rust-mir-verify] {}", e);
|
||||
}
|
||||
panic!(
|
||||
"MIR verification failed for Stage1UsingResolverModulesMapContinueBreakLookup"
|
||||
);
|
||||
panic!("MIR verification failed for Stage1UsingResolverModulesMapContinueBreakLookup");
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,11 +76,7 @@ fn mir_static_main_box_executes_void_path_with_guard() {
|
||||
|
||||
// Just ensure the symbol exists; methodization may optimize away the actual call.
|
||||
assert!(
|
||||
compiled
|
||||
.module
|
||||
.functions
|
||||
.keys()
|
||||
.any(|k| k == "Main._nop/0"),
|
||||
compiled.module.functions.keys().any(|k| k == "Main._nop/0"),
|
||||
"Main._nop/0 should remain defined"
|
||||
);
|
||||
}
|
||||
|
||||
@ -6,38 +6,40 @@ pub mod identical_exec;
|
||||
pub mod identical_exec_collections;
|
||||
pub mod identical_exec_instance;
|
||||
pub mod identical_exec_string;
|
||||
pub mod mir_breakfinder_ssa;
|
||||
pub mod mir_funcscanner_skip_ws;
|
||||
pub mod mir_funcscanner_parse_params_trim_min;
|
||||
pub mod mir_funcscanner_trim_min;
|
||||
pub mod mir_funcscanner_ssa;
|
||||
pub mod mir_joinir_min; // Phase 26-H: JoinIR型定義妥当性確認
|
||||
pub mod mir_joinir_skip_ws; // Phase 27.0: minimal_ssa_skip_ws JoinIR変換
|
||||
pub mod mir_joinir_funcscanner_trim; // Phase 27.1: FuncScannerBox.trim JoinIR変換
|
||||
pub mod mir_joinir_stage1_using_resolver_min; // Phase 27.12: Stage1UsingResolverBox.resolve_for_source JoinIR変換
|
||||
pub mod mir_joinir_funcscanner_append_defs; // Phase 27.14: FuncScannerBox._append_defs JoinIR変換
|
||||
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
|
||||
pub mod json_lint_stringutils_min_vm; // Phase 21.7++: using StringUtils alias resolution fix
|
||||
pub mod mir_breakfinder_ssa;
|
||||
pub mod mir_funcscanner_parse_params_trim_min;
|
||||
pub mod mir_funcscanner_skip_ws;
|
||||
pub mod mir_funcscanner_ssa;
|
||||
pub mod mir_funcscanner_trim_min;
|
||||
pub mod mir_joinir_funcscanner_append_defs; // Phase 27.14: FuncScannerBox._append_defs JoinIR変換
|
||||
pub mod mir_joinir_funcscanner_trim; // Phase 27.1: FuncScannerBox.trim JoinIR変換
|
||||
pub mod mir_joinir_min; // Phase 26-H: JoinIR型定義妥当性確認
|
||||
pub mod mir_joinir_skip_ws; // Phase 27.0: minimal_ssa_skip_ws JoinIR変換
|
||||
pub mod mir_joinir_stage1_using_resolver_min; // Phase 27.12: Stage1UsingResolverBox.resolve_for_source JoinIR変換
|
||||
pub mod mir_joinir_stageb_body; // Phase 28: StageBBodyExtractorBox.build_body_src JoinIR変換
|
||||
pub mod mir_joinir_stageb_funcscanner; // Phase 28: StageBFuncScannerBox.scan_all_boxes JoinIR変換
|
||||
pub mod mir_locals_ssa;
|
||||
pub mod mir_loopform_complex;
|
||||
pub mod mir_loopform_conditional_reassign;
|
||||
pub mod mir_loopform_exit_phi;
|
||||
pub mod mir_loopform_complex;
|
||||
pub mod mir_static_box_naming;
|
||||
pub mod mir_stage1_cli_emit_program_min;
|
||||
pub mod mir_stage1_staticcompiler_receiver; // Phase 25.1: StaticCompiler receiver型推論バグ回帰防止
|
||||
pub mod mir_stage1_using_resolver_verify;
|
||||
pub mod json_lint_stringutils_min_vm; // Phase 21.7++: using StringUtils alias resolution fix
|
||||
pub mod namingbox_static_method_id; // Phase 21.7++ Phase 1: StaticMethodId structure tests
|
||||
pub mod stage1_cli_entry_ssa_smoke;
|
||||
pub mod mir_stageb_like_args_length;
|
||||
pub mod mir_stageb_loop_break_continue;
|
||||
pub mod mir_stageb_string_utils_skip_ws; // Phase 25.1: skip_ws Void < 0 TypeError 再現
|
||||
pub mod mir_static_box_naming;
|
||||
pub mod mir_value_kind; // Phase 26-A-5: ValueId型安全化統合テスト
|
||||
pub mod namingbox_static_method_id; // Phase 21.7++ Phase 1: StaticMethodId structure tests
|
||||
pub mod nyash_abi_basic;
|
||||
pub mod parser_static_box_members;
|
||||
pub mod plugin_hygiene;
|
||||
pub mod policy_mutdeny;
|
||||
pub mod stage1_cli_entry_ssa_smoke;
|
||||
pub mod sugar_basic_test;
|
||||
pub mod sugar_coalesce_test;
|
||||
pub mod sugar_comp_assign_test;
|
||||
|
||||
@ -59,11 +59,7 @@ fn test_with_arity() {
|
||||
|
||||
#[test]
|
||||
fn test_round_trip() {
|
||||
let cases = vec![
|
||||
"Main._nop/0",
|
||||
"StringUtils.starts_with/2",
|
||||
"Console.log/1",
|
||||
];
|
||||
let cases = vec!["Main._nop/0", "StringUtils.starts_with/2", "Console.log/1"];
|
||||
|
||||
for case in cases {
|
||||
let id = StaticMethodId::parse(case).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user