refactor(funcscanner): Region+next_i パターン統一 & SSA テスト追加
**FuncScanner .hako 側改善**: - scan_all_boxes を Region + next_i 形式に統一(continue 多発による SSA/PHI 複雑さ削減) - インデント修正(タブ→スペース統一) - デバッグ print 削除 **SSA テスト追加**: - lang/src/compiler/tests/funcscanner_scan_methods_min.hako - src/tests/mir_funcscanner_ssa.rs (scan_methods & fib_min SSA デバッグテスト) **Phase 25.3 ドキュメント**: - docs/development/roadmap/phases/phase-25.3-funcscanner/ 追加 **関連**: Phase 25.3 FuncScanner 箱化準備作業 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -12,90 +12,91 @@ static box FuncScannerBox {
|
||||
return me._scan_methods(source, box_name, 1, 0)
|
||||
}
|
||||
|
||||
// Scan all static box definitions and collect their methods.
|
||||
method scan_all_boxes(source) {
|
||||
// source が null の場合はスキャン対象がないので空配列を返すよ。
|
||||
if source == null { return new ArrayBox() }
|
||||
local defs = new ArrayBox()
|
||||
local s = "" + source
|
||||
// Scan all static box definitions and collect their methods.
|
||||
method scan_all_boxes(source) {
|
||||
// source が null の場合はスキャン対象がないので空配列を返すよ。
|
||||
if source == null { return new ArrayBox() }
|
||||
local defs = new ArrayBox()
|
||||
local s = "" + source
|
||||
local n = s.length()
|
||||
// DEBUG: 一時的に常時トレースを有効化(Stage‑B fib 用の挙動観測)
|
||||
print("[funcscan/scan_all_boxes] source_len=" + ("" + n))
|
||||
local i = 0
|
||||
local in_str = 0
|
||||
local esc = 0
|
||||
local in_line = 0
|
||||
local in_block = 0
|
||||
|
||||
// Region + next_i 形式に統一して、ループ本体での多重 continue による
|
||||
// SSA/PHI の複雑さを下げる。
|
||||
loop(i < n) {
|
||||
local next_i = i + 1
|
||||
local ch = s.substring(i, i + 1)
|
||||
|
||||
if in_line == 1 {
|
||||
if ch == "\n" { in_line = 0 }
|
||||
i = i + 1
|
||||
continue
|
||||
}
|
||||
if in_block == 1 {
|
||||
} else if in_block == 1 {
|
||||
if ch == "*" && i + 1 < n && s.substring(i + 1, i + 2) == "/" {
|
||||
in_block = 0
|
||||
i = i + 2
|
||||
continue
|
||||
next_i = i + 2
|
||||
}
|
||||
} else if in_str == 1 {
|
||||
if esc == 1 {
|
||||
esc = 0
|
||||
} else if ch == "\\" {
|
||||
esc = 1
|
||||
} else if ch == "\"" {
|
||||
in_str = 0
|
||||
}
|
||||
} else {
|
||||
if ch == "\"" {
|
||||
in_str = 1
|
||||
} else if ch == "/" && i + 1 < n {
|
||||
local ch2 = s.substring(i + 1, i + 2)
|
||||
if ch2 == "/" {
|
||||
in_line = 1
|
||||
next_i = i + 2
|
||||
} else if ch2 == "*" {
|
||||
in_block = 1
|
||||
next_i = i + 2
|
||||
}
|
||||
} else {
|
||||
if i + 3 <= n && s.substring(i, i + 3) == "box" && me._kw_boundary_before(s, i) == 1 && me._kw_boundary_after(s, i + 3) == 1 {
|
||||
local cursor = i + 3
|
||||
cursor = me._skip_whitespace(s, cursor)
|
||||
local name_start = cursor
|
||||
loop(cursor < n) {
|
||||
local ch_name = s.substring(cursor, cursor + 1)
|
||||
if me._is_ident_char(ch_name) == 1 { cursor = cursor + 1 } else { break }
|
||||
}
|
||||
local box_name = s.substring(name_start, cursor)
|
||||
if box_name == "" {
|
||||
next_i = cursor
|
||||
} else {
|
||||
cursor = me._skip_whitespace(s, cursor)
|
||||
if cursor >= n || s.substring(cursor, cursor + 1) != "{" {
|
||||
next_i = cursor
|
||||
} else {
|
||||
local close_idx = me._find_matching_brace(s, cursor)
|
||||
if close_idx < 0 {
|
||||
// マッチしない場合はこれ以上スキャンしても意味がないのでループ終了。
|
||||
i = n
|
||||
next_i = n
|
||||
} else {
|
||||
local body = s.substring(cursor + 1, close_idx)
|
||||
local skip_main = 0
|
||||
if box_name == "Main" { skip_main = 1 }
|
||||
local include_me = 0
|
||||
if box_name != "Main" { include_me = 1 }
|
||||
local defs_box = me._scan_methods(body, box_name, skip_main, include_me)
|
||||
me._append_defs(defs, defs_box)
|
||||
next_i = close_idx + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
i = i + 1
|
||||
continue
|
||||
}
|
||||
if in_str == 1 {
|
||||
if esc == 1 { esc = 0 i = i + 1 continue }
|
||||
if ch == "\\" { esc = 1 i = i + 1 continue }
|
||||
if ch == "\"" { in_str = 0 i = i + 1 continue }
|
||||
i = i + 1
|
||||
continue
|
||||
}
|
||||
if ch == "\"" { in_str = 1 i = i + 1 continue }
|
||||
if ch == "/" && i + 1 < n {
|
||||
local ch2 = s.substring(i + 1, i + 2)
|
||||
if ch2 == "/" { in_line = 1 i = i + 2 continue }
|
||||
if ch2 == "*" { in_block = 1 i = i + 2 continue }
|
||||
}
|
||||
|
||||
// DEBUG: "box" キーワード候補をチェック(Stage‑B fib 用)
|
||||
if i + 3 <= n {
|
||||
local candidate = s.substring(i, i + 3)
|
||||
if candidate == "box" {
|
||||
print("[funcscan/box_candidate] i=" + ("" + i) + " candidate=" + candidate)
|
||||
}
|
||||
}
|
||||
if s.substring(i, i + 3) == "box" && me._kw_boundary_before(s, i) == 1 && me._kw_boundary_after(s, i + 3) == 1 {
|
||||
local cursor = i + 3
|
||||
cursor = me._skip_whitespace(s, cursor)
|
||||
local name_start = cursor
|
||||
loop(cursor < n) {
|
||||
local ch_name = s.substring(cursor, cursor + 1)
|
||||
if me._is_ident_char(ch_name) == 1 { cursor = cursor + 1 } else { break }
|
||||
}
|
||||
local box_name = s.substring(name_start, cursor)
|
||||
if box_name == "" {
|
||||
i = cursor
|
||||
continue
|
||||
}
|
||||
cursor = me._skip_whitespace(s, cursor)
|
||||
if cursor >= n || s.substring(cursor, cursor + 1) != "{" {
|
||||
i = cursor
|
||||
continue
|
||||
}
|
||||
local close_idx = me._find_matching_brace(s, cursor)
|
||||
if close_idx < 0 { break }
|
||||
local body = s.substring(cursor + 1, close_idx)
|
||||
local skip_main = 0
|
||||
if box_name == "Main" { skip_main = 1 }
|
||||
local include_me = 0
|
||||
if box_name != "Main" { include_me = 1 }
|
||||
local defs_box = me._scan_methods(body, box_name, skip_main, include_me)
|
||||
me._append_defs(defs, defs_box)
|
||||
i = close_idx + 1
|
||||
continue
|
||||
}
|
||||
|
||||
i = i + 1
|
||||
i = next_i
|
||||
}
|
||||
return defs
|
||||
}
|
||||
@ -164,7 +165,8 @@ static box FuncScannerBox {
|
||||
|
||||
// Extract params (minimal: comma-separated names)
|
||||
local params_str = s.substring(lparen + 1, rparen)
|
||||
local params = me._parse_params(params_str)
|
||||
// static helper として扱う(me ではなく FuncScannerBox に直接委譲)。
|
||||
local params = FuncScannerBox._parse_params(params_str)
|
||||
if include_me == 1 {
|
||||
local first = ""
|
||||
if params.length() > 0 { first = "" + params.get(0) }
|
||||
@ -235,8 +237,9 @@ static box FuncScannerBox {
|
||||
// Extract method body (inside braces)
|
||||
local method_body = s.substring(lbrace + 1, rbrace)
|
||||
|
||||
method_body = me._strip_comments(method_body)
|
||||
method_body = me._trim(method_body)
|
||||
// コメント除去と trim も static helper として扱う。
|
||||
method_body = FuncScannerBox._strip_comments(method_body)
|
||||
method_body = FuncScannerBox._trim(method_body)
|
||||
|
||||
// Parse method body to JSON (statement list)
|
||||
local body_json = null
|
||||
@ -304,14 +307,18 @@ static box FuncScannerBox {
|
||||
|
||||
method _find_matching_brace(s, open_idx) {
|
||||
local n = s.length()
|
||||
local i = open_idx
|
||||
if open_idx < 0 || open_idx >= n { return -1 }
|
||||
// open_idx 以降だけを対象に走査することで、前方の構造に依存しないようにする。
|
||||
local subs = s.substring(open_idx, n)
|
||||
local m = subs.length()
|
||||
local i = 0
|
||||
local depth = 0
|
||||
local in_str = 0
|
||||
local esc = 0
|
||||
local in_line = 0
|
||||
local in_block = 0
|
||||
loop(i < n) {
|
||||
local ch = s.substring(i, i + 1)
|
||||
loop(i < m) {
|
||||
local ch = subs.substring(i, i + 1)
|
||||
if in_line == 1 {
|
||||
if ch == "\n" { in_line = 0 }
|
||||
i = i + 1
|
||||
@ -334,8 +341,8 @@ static box FuncScannerBox {
|
||||
continue
|
||||
}
|
||||
if ch == "\"" { in_str = 1 i = i + 1 continue }
|
||||
if ch == "/" && i + 1 < n {
|
||||
local ch2 = s.substring(i + 1, i + 2)
|
||||
if ch == "/" && i + 1 < m {
|
||||
local ch2 = subs.substring(i + 1, i + 2)
|
||||
if ch2 == "/" { in_line = 1 i = i + 2 continue }
|
||||
if ch2 == "*" { in_block = 1 i = i + 2 continue }
|
||||
}
|
||||
@ -347,7 +354,7 @@ static box FuncScannerBox {
|
||||
if ch == "}" {
|
||||
depth = depth - 1
|
||||
i = i + 1
|
||||
if depth == 0 { return i - 1 }
|
||||
if depth == 0 { return open_idx + i - 1 }
|
||||
continue
|
||||
}
|
||||
i = i + 1
|
||||
|
||||
43
lang/src/compiler/tests/funcscanner_scan_methods_min.hako
Normal file
43
lang/src/compiler/tests/funcscanner_scan_methods_min.hako
Normal file
@ -0,0 +1,43 @@
|
||||
// funcscanner_scan_methods_min.hako — FuncScannerBox._scan_methods minimal harness
|
||||
//
|
||||
// 目的:
|
||||
// - static box TestBox/Main を含むソースから TestBox.body 部分だけを切り出し、
|
||||
// FuncScannerBox._scan_methods(source, "TestBox", 0, 1) を直接呼び出す。
|
||||
// - params 部分のパースと _parse_params/_trim の呼び出しが SSA 的に安全であることを確認する。
|
||||
//
|
||||
// 振る舞い:
|
||||
// - fib と同等の TestBox/Main を src に埋め込む。
|
||||
// - FuncScannerBox._find_matching_brace で TestBox の '{'〜'}' 範囲を取得。
|
||||
// - 本文だけを body1 として抜き出し、FuncScannerBox._scan_methods に渡す。
|
||||
// - defs.len と各定義の box/name をログに出力する(Stage‑B 側と比較しやすくする)。
|
||||
|
||||
using lang.compiler.entry.func_scanner as FuncScannerBox
|
||||
|
||||
static box Main {
|
||||
method main(args) {
|
||||
local src = "static box TestBox {\n method fib(n) {\n local i = 0\n local a = 0\n local b = 1\n loop(i < n) {\n local t = a + b\n a = b\n b = t\n i = i + 1\n }\n return b\n }\n}\n\nstatic box Main {\n method main(args) {\n local t = new TestBox()\n return t.fib(6)\n }\n}\n"
|
||||
|
||||
// TestBox 本体の brace 範囲を FuncScannerBox の実装で検出
|
||||
local open1 = 19
|
||||
local close1 = FuncScannerBox._find_matching_brace(src, open1)
|
||||
print("[scan_methods] brace1 open=" + ("" + open1) + " close=" + ("" + close1))
|
||||
if close1 < 0 { return 1 }
|
||||
|
||||
// "box TestBox {" の直後から close1 直前までを body1 として切り出す
|
||||
local body1 = src.substring(open1 + 1, close1)
|
||||
print("[scan_methods] body1_len=" + ("" + body1.length()))
|
||||
|
||||
// FuncScannerBox._scan_methods を直接呼び出してメソッド定義を抽出
|
||||
local defs1 = FuncScannerBox._scan_methods(body1, "TestBox", 0, 1)
|
||||
local n1 = defs1.length()
|
||||
print("[scan_methods] defs1.len=" + ("" + n1))
|
||||
local i = 0
|
||||
loop(i < n1) {
|
||||
local d = defs1.get(i)
|
||||
print("[scan_methods] def1[" + ("" + i) + "] box=" + ("" + d.get("box")) + " name=" + ("" + d.get("name")))
|
||||
i = i + 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user