From 0dc8510daf92b5038d118bc00962dde8eeca2cc3 Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Thu, 20 Nov 2025 08:03:05 +0900 Subject: [PATCH] =?UTF-8?q?debug(stageb):=20=E3=82=BB=E3=83=B3=E3=83=81?= =?UTF-8?q?=E3=83=8D=E3=83=AB=E8=BF=BD=E5=8A=A0=E3=81=A7VM=E3=83=90?= =?UTF-8?q?=E3=82=B0=E7=89=B9=E5=AE=9A=20-=20using=E7=B5=8C=E7=94=B1static?= =?UTF-8?q?=20box=E5=86=85loop=E4=B8=8D=E5=AE=9F=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 🔍 調査結果 ### ✅ 確認事項 - **本物の実装が呼ばれている**: SENTINEL出力で確認済み - 🔥 SENTINEL_SKIP_WS_CALLED!!! - 🎯 SENTINEL_KW_BOUNDARY_BEFORE_CALLED!!! - 🎯 SENTINEL_KW_BOUNDARY_AFTER_CALLED!!! - 🔤 SENTINEL_IS_IDENT_CHAR_CALLED!!! ### 🐛 重大バグ発見 **症状**: `FuncScannerBox.skip_whitespace` 内の `loop(1 == 1)` が実行されない **証拠**: ``` [skip_ws] START idx=10 s.length()=173 [skip_ws] i=10 n=173 [skip_ws] RETURN i=10 ← ループボディが実行されず即座にreturn ``` - `[skip_ws] LOOP-TOP i=10` が**一度も出力されない** - loop(1 == 1) の無限ループすら実行されない **影響範囲**: - box_name抽出失敗(空文字列) - defs生成失敗(defs_len=0) - canary テスト失敗 **問題の本質**: - using 経由で読み込まれたモジュールの static box 内 - 静的メソッド呼び出し (`FuncScannerBox.skip_whitespace(...)`) - loop 構文が VM/MIR レベルで実行されない ## 🔧 修正内容 1. **センチネル追加**: 4箇所に明確な出力追加 - skip_whitespace, kw_boundary_before, kw_boundary_after, is_ident_char 2. **呼び出し修正**: `me.scan_all_boxes` → `StageBFuncScannerBox.scan_all_boxes` ## 📊 次のステップ VM/MIR レイヤーでの loop 構文実装確認が必要 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- lang/src/compiler/entry/compiler_stageb.hako | 2 +- lang/src/compiler/entry/func_scanner.hako | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/lang/src/compiler/entry/compiler_stageb.hako b/lang/src/compiler/entry/compiler_stageb.hako index fc5fb33a..00c79e87 100644 --- a/lang/src/compiler/entry/compiler_stageb.hako +++ b/lang/src/compiler/entry/compiler_stageb.hako @@ -1214,7 +1214,7 @@ static box StageBDriverBox { tracer.log("StageBDriverBox.main:func_scan src_head=" + head) } - local methods = me.scan_all_boxes(src) + local methods = StageBFuncScannerBox.scan_all_boxes(src) { local cnt = 0 diff --git a/lang/src/compiler/entry/func_scanner.hako b/lang/src/compiler/entry/func_scanner.hako index 4f1665fd..55b5b8bd 100644 --- a/lang/src/compiler/entry/func_scanner.hako +++ b/lang/src/compiler/entry/func_scanner.hako @@ -83,13 +83,18 @@ static box FuncScannerBox { } else { if i + 3 <= n && s.substring(i, i + 3) == "box" && FuncScannerBox.kw_boundary_before(s, i) == 1 && FuncScannerBox.kw_boundary_after(s, i + 3) == 1 { local cursor = i + 3 + print("[DEBUG] box keyword found at i=" + ("" + i)) cursor = FuncScannerBox.skip_whitespace(s, cursor) + print("[DEBUG] after skip_whitespace: cursor=" + ("" + cursor)) local name_start = cursor loop(cursor < n) { local ch_name = s.substring(cursor, cursor + 1) + print("[DEBUG] cursor=" + ("" + cursor) + " ch_name='" + ch_name + "' is_ident=" + ("" + FuncScannerBox.is_ident_char(ch_name))) if FuncScannerBox.is_ident_char(ch_name) == 1 { cursor = cursor + 1 } else { break } } + print("[DEBUG] name_start=" + ("" + name_start) + " cursor=" + ("" + cursor) + " n=" + ("" + n)) local box_name = s.substring(name_start, cursor) + print("[DEBUG] box_name='" + box_name + "' len=" + ("" + box_name.length())) if box_name == "" { next_i = cursor } else { @@ -302,18 +307,28 @@ static box FuncScannerBox { // Helper: 空白文字(space/tab/newline/CR)を idx 位置からスキップ // 戻り値: スキップ後の位置(空白でない文字の位置、または文字列末尾) method skip_whitespace(s, idx) { + print("🔥🔥🔥 SENTINEL_SKIP_WS_CALLED!!! 🔥🔥🔥") + print("[skip_ws] START idx=" + ("" + idx) + " s.length()=" + ("" + s.length())) local i = idx local n = s.length() - loop(i < n) { + print("[skip_ws] i=" + ("" + i) + " n=" + ("" + n)) + // WORKAROUND: Changed from loop(i < n) to loop with internal if check + // Original: loop(i < n) { ... } was not executing body even when condition was true! + loop(1 == 1) { + print("[skip_ws] LOOP-TOP i=" + ("" + i)) + if i >= n { break } local ch = s.substring(i, i + 1) + print("[skip_ws] LOOP i=" + ("" + i) + " ch='" + ch + "'") if ch == " " || ch == "\t" || ch == "\n" || ch == "\r" { i = i + 1 } else { break } } + print("[skip_ws] RETURN i=" + ("" + i)) return i } // Helper: キーワード前の境界チェック("box" などが識別子の一部でないことを確認) // 戻り値: 1=境界OK(キーワードとして有効), 0=境界NG(識別子の一部) method kw_boundary_before(s, idx) { + print("🎯 SENTINEL_KW_BOUNDARY_BEFORE_CALLED!!!") if idx <= 0 { return 1 } local ch = s.substring(idx - 1, idx) if FuncScannerBox.is_ident_char(ch) == 1 { return 0 } @@ -323,6 +338,7 @@ static box FuncScannerBox { // Helper: キーワード後の境界チェック("box" などが識別子の一部でないことを確認) // 戻り値: 1=境界OK(キーワードとして有効), 0=境界NG(識別子の一部) method kw_boundary_after(s, idx) { + print("🎯 SENTINEL_KW_BOUNDARY_AFTER_CALLED!!!") if idx >= s.length() { return 1 } local ch = s.substring(idx, idx + 1) if FuncScannerBox.is_ident_char(ch) == 1 { return 0 } @@ -332,6 +348,7 @@ static box FuncScannerBox { // Helper: 識別子として有効な文字かチェック(0-9, A-Z, a-z, _) // 戻り値: 1=識別子文字, 0=非識別子文字 method is_ident_char(ch) { + print("🔤 SENTINEL_IS_IDENT_CHAR_CALLED!!!") if ch == null || ch == "" { return 0 } if ch >= "0" && ch <= "9" { return 1 } if ch >= "A" && ch <= "Z" { return 1 }