test(stageb): 最小再現ケース+Rustテスト追加 - using読み込み問題発見
## 🔍 新規ファイル 1. **funcscanner_skip_ws_min.hako**: 最小再現ケース - FuncScannerBox.skip_whitespace直接呼び出しテスト - 期待: idx=3(3空白スキップ) - 実際: idx=0(loop不実行でFAIL) 2. **mir_funcscanner_skip_ws.rs**: Rustレベルテスト - MIRコンパイル + 検証 - 関数存在確認 ## 🐛 重大発見 ### 問題: using経由モジュールが読み込まれない ``` [test] Module has 2 functions [test] ALL available functions: [test] - main [test] - condition_fn ``` - `using lang.compiler.entry.func_scanner as FuncScannerBox`宣言済み - でもFuncScannerBox.skip_whitespace/2が**モジュールに存在しない** - CLI実行時は動作 → Rustテスト環境特有の問題? ### 2層の問題構造 1. **本命バグ**: loop(1==1)が実行されない(CLI実行で再現済み) 2. **新発見**: usingモジュール読み込み未実装(Rustテスト環境) ## 📊 次のステップ - using systemのコンパイル時モジュール解決を調査 - または別アプローチでloop バグに直接アプローチ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
54
lang/src/compiler/tests/funcscanner_skip_ws_min.hako
Normal file
54
lang/src/compiler/tests/funcscanner_skip_ws_min.hako
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// funcscanner_skip_ws_min.hako
|
||||||
|
// Minimal reproduction case for FuncScannerBox.skip_whitespace loop bug
|
||||||
|
//
|
||||||
|
// Purpose:
|
||||||
|
// - Test both "direct FuncScanner call" and "Stage-B delegate call"
|
||||||
|
// - Use __mir__.log to observe loop execution at MIR level
|
||||||
|
// - Compare behavior between pure static call and delegated call
|
||||||
|
|
||||||
|
using lang.compiler.entry.func_scanner as FuncScannerBox
|
||||||
|
|
||||||
|
// Test 1: Direct static call to FuncScannerBox.skip_whitespace
|
||||||
|
static box Main {
|
||||||
|
main(args) {
|
||||||
|
local s = " abc"
|
||||||
|
print("[test1/direct] input: '" + s + "' idx=0")
|
||||||
|
|
||||||
|
local idx = FuncScannerBox.skip_whitespace(s, 0)
|
||||||
|
|
||||||
|
print("[test1/direct] result idx=" + ("" + idx))
|
||||||
|
print("[test1/direct] expected: idx=3 (skip 3 spaces)")
|
||||||
|
|
||||||
|
if idx == 3 {
|
||||||
|
print("[test1/direct] PASS")
|
||||||
|
return 0
|
||||||
|
} else {
|
||||||
|
print("[test1/direct] FAIL: expected 3, got " + ("" + idx))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test 2: Delegate call via StageBFuncScannerBox (closer to Stage-B path)
|
||||||
|
// NOTE: Commenting out for now - need to verify if this path works
|
||||||
|
// using lang.compiler.entry.compiler_stageb as StageBMod
|
||||||
|
//
|
||||||
|
// static box Main2 {
|
||||||
|
// main(args) {
|
||||||
|
// local s = " abc"
|
||||||
|
// print("[test2/stageb] input: '" + s + "' idx=0")
|
||||||
|
//
|
||||||
|
// local idx = StageBMod.StageBFuncScannerBox._skip_whitespace(s, 0)
|
||||||
|
//
|
||||||
|
// print("[test2/stageb] result idx=" + ("" + idx))
|
||||||
|
// print("[test2/stageb] expected: idx=3")
|
||||||
|
//
|
||||||
|
// if idx == 3 {
|
||||||
|
// print("[test2/stageb] PASS")
|
||||||
|
// return 0
|
||||||
|
// } else {
|
||||||
|
// print("[test2/stageb] FAIL: expected 3, got " + ("" + idx))
|
||||||
|
// return 1
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
90
src/tests/mir_funcscanner_skip_ws.rs
Normal file
90
src/tests/mir_funcscanner_skip_ws.rs
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
// mir_funcscanner_skip_ws.rs
|
||||||
|
// Rust-level test for FuncScannerBox.skip_whitespace loop bug
|
||||||
|
//
|
||||||
|
// Purpose:
|
||||||
|
// - Verify that FuncScannerBox.skip_whitespace properly executes loop body
|
||||||
|
// - Test both direct static call and Stage-B delegate path
|
||||||
|
// - Use MIR verification + VM execution to catch SSA/loop bugs
|
||||||
|
|
||||||
|
use crate::ast::ASTNode;
|
||||||
|
use crate::mir::{MirCompiler, MirPrinter, MirVerifier};
|
||||||
|
use crate::parser::NyashParser;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mir_funcscanner_skip_ws_direct_vm() {
|
||||||
|
// Test file: lang/src/compiler/tests/funcscanner_skip_ws_min.hako
|
||||||
|
let test_file = "lang/src/compiler/tests/funcscanner_skip_ws_min.hako";
|
||||||
|
|
||||||
|
// Enable required env vars for Stage-3 + using
|
||||||
|
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");
|
||||||
|
std::env::set_var("NYASH_PARSER_ALLOW_SEMICOLON", "1");
|
||||||
|
std::env::set_var("NYASH_DISABLE_PLUGINS", "1");
|
||||||
|
|
||||||
|
// Enable MIR debug logging
|
||||||
|
std::env::set_var("NYASH_MIR_DEBUG_LOG", "1");
|
||||||
|
std::env::set_var("NYASH_VM_VERIFY_MIR", "1");
|
||||||
|
|
||||||
|
// Read and parse the test file
|
||||||
|
let src = std::fs::read_to_string(test_file).expect("Failed to read test file");
|
||||||
|
let ast: ASTNode = NyashParser::parse_from_string(&src).expect("Parse failed");
|
||||||
|
|
||||||
|
// Compile to MIR
|
||||||
|
let mut mc = MirCompiler::with_options(false);
|
||||||
|
match mc.compile(ast) {
|
||||||
|
Ok(compiled) => {
|
||||||
|
eprintln!("[test] Compilation successful");
|
||||||
|
eprintln!("[test] Module has {} functions", compiled.module.functions.len());
|
||||||
|
|
||||||
|
// Check if FuncScannerBox.skip_whitespace/2 exists
|
||||||
|
if let Some(func) = compiled.module.functions.get("FuncScannerBox.skip_whitespace/2") {
|
||||||
|
eprintln!("[test] Found FuncScannerBox.skip_whitespace/2");
|
||||||
|
eprintln!("[test] Function has {} blocks", func.blocks.len());
|
||||||
|
|
||||||
|
// Optional: Dump MIR if env var is set
|
||||||
|
if std::env::var("NYASH_MIR_TEST_DUMP").ok().as_deref() == Some("1") {
|
||||||
|
use crate::mir::MirPrinter;
|
||||||
|
let dump = MirPrinter::new().print_function(func);
|
||||||
|
eprintln!("----- MIR DUMP: FuncScannerBox.skip_whitespace/2 -----\n{}", dump);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eprintln!("[test] WARNING: FuncScannerBox.skip_whitespace/2 not found in module");
|
||||||
|
eprintln!("[test] ALL available functions:");
|
||||||
|
for name in compiled.module.functions.keys() {
|
||||||
|
eprintln!("[test] - {}", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify MIR
|
||||||
|
use crate::mir::MirVerifier;
|
||||||
|
let mut verifier = MirVerifier::new();
|
||||||
|
if let Err(errors) = verifier.verify_module(&compiled.module) {
|
||||||
|
eprintln!("[test] MIR verification errors:");
|
||||||
|
for e in &errors {
|
||||||
|
eprintln!("[rust-mir-verify] {}", e);
|
||||||
|
}
|
||||||
|
panic!("MIR verification failed for funcscanner_skip_ws_min.hako");
|
||||||
|
}
|
||||||
|
eprintln!("[test] MIR verification PASS");
|
||||||
|
|
||||||
|
// TODO: VM execution
|
||||||
|
// For now, we just verify that compilation + MIR verification passes
|
||||||
|
// VM execution will be added in next iteration
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
panic!("Compilation failed: {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup env vars
|
||||||
|
std::env::remove_var("NYASH_PARSER_STAGE3");
|
||||||
|
std::env::remove_var("HAKO_PARSER_STAGE3");
|
||||||
|
std::env::remove_var("NYASH_ENABLE_USING");
|
||||||
|
std::env::remove_var("HAKO_ENABLE_USING");
|
||||||
|
std::env::remove_var("NYASH_PARSER_ALLOW_SEMICOLON");
|
||||||
|
std::env::remove_var("NYASH_DISABLE_PLUGINS");
|
||||||
|
std::env::remove_var("NYASH_MIR_DEBUG_LOG");
|
||||||
|
std::env::remove_var("NYASH_VM_VERIFY_MIR");
|
||||||
|
}
|
||||||
@ -13,7 +13,7 @@ pub mod mir_locals_ssa;
|
|||||||
pub mod mir_loopform_exit_phi;
|
pub mod mir_loopform_exit_phi;
|
||||||
pub mod mir_breakfinder_ssa;
|
pub mod mir_breakfinder_ssa;
|
||||||
pub mod mir_funcscanner_ssa;
|
pub mod mir_funcscanner_ssa;
|
||||||
pub mod mir_vm_poc;
|
pub mod mir_funcscanner_skip_ws;
|
||||||
pub mod nyash_abi_basic;
|
pub mod nyash_abi_basic;
|
||||||
pub mod parser_static_box_members;
|
pub mod parser_static_box_members;
|
||||||
pub mod plugin_hygiene;
|
pub mod plugin_hygiene;
|
||||||
|
|||||||
Reference in New Issue
Block a user