hv1: early-exit at main (no plugin init); tokenizer: Stage-3 single-quote + full escapes (\/ \b \f \' \r fix); builder: route BinOp via SSOT emit_binop_to_dst; hv1 verify canary route (builder→Core); docs: phase-20.39 updates
This commit is contained in:
83
lang/src/mir/builder/internal/loop_scan_box.hako
Normal file
83
lang/src/mir/builder/internal/loop_scan_box.hako
Normal file
@ -0,0 +1,83 @@
|
||||
// loop_scan_box.hako — If/Compare + then/else 範囲スキャンの小箱
|
||||
|
||||
using "hako.mir.builder.internal.prog_scan" as ProgScanBox
|
||||
using ProgScanBox as Scan
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
|
||||
static box LoopScanBox {
|
||||
// 抽出: cond Compare から Var 名(lhs/rhs いずれか)を取得
|
||||
find_loop_var_name(s, k_cmp) {
|
||||
local varname = null
|
||||
local kl = ("" + s).indexOf("\"lhs\":{", k_cmp)
|
||||
local kr = ("" + s).indexOf("\"rhs\":{", k_cmp)
|
||||
if kl >= 0 && ("" + s).indexOf("\"type\":\"Var\"", kl) >= 0 { varname = Scan.read_quoted_after_key(s, kl, "name") }
|
||||
if varname == null && kr >= 0 && ("" + s).indexOf("\"type\":\"Var\"", kr) >= 0 { varname = Scan.read_quoted_after_key(s, kr, "name") }
|
||||
return varname
|
||||
}
|
||||
|
||||
// '!=' + else [Break/Continue] パターンからX値を抽出(最小サブセット)
|
||||
// sentinel: "Break" | "Continue"
|
||||
extract_ne_else_sentinel_value(s, sentinel, k_loop, varname) {
|
||||
local st = "\"type\":\"" + sentinel + "\""
|
||||
local ks = ("" + s).indexOf(st, k_loop)
|
||||
if ks < 0 { return null }
|
||||
// 直前の If と Compare を見つける(同一 then/else 内の近傍に限定)
|
||||
local kif = ("" + s).lastIndexOf("\"type\":\"If\"", ks)
|
||||
if kif < 0 { return null }
|
||||
local kcmp = ("" + s).lastIndexOf("\"type\":\"Compare\"", ks)
|
||||
if kcmp < 0 || kcmp < kif { return null }
|
||||
local op = Scan.read_quoted_after_key(s, kcmp, "op"); if op == null || op != "!=" { return null }
|
||||
// else 範囲の配列区間を特定
|
||||
local kth = JsonFragBox.index_of_from(s, "\"then\":", kif); if kth < 0 { return null }
|
||||
local lb_then = JsonFragBox.index_of_from(s, "[", kth); if lb_then < 0 { return null }
|
||||
local rb_then = JsonFragBox._seek_array_end(s, lb_then); if rb_then < 0 { return null }
|
||||
local kel = JsonFragBox.index_of_from(s, "\"else\":", rb_then); if kel < 0 { return null }
|
||||
local lb_else = JsonFragBox.index_of_from(s, "[", kel); if lb_else < 0 { return null }
|
||||
local rb_else = JsonFragBox._seek_array_end(s, lb_else); if rb_else < 0 { return null }
|
||||
// sentinel が else ブロック中にあること
|
||||
if !(ks > lb_else && ks < rb_else) { return null }
|
||||
// 比較の反対側 Int を抽出(lhs=Var(varname) → rhs Int、rhs=Var → lhs Int)
|
||||
local has_lhs = ("" + s).indexOf("\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kcmp) >= 0
|
||||
local has_rhs = ("" + s).indexOf("\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kcmp) >= 0
|
||||
if !has_lhs && !has_rhs { return null }
|
||||
if has_lhs {
|
||||
local kr = ("" + s).indexOf("\"rhs\":{", kcmp); if kr < 0 { return null }
|
||||
local kt = ("" + s).indexOf("\"type\":\"Int\"", kr); if kt < 0 { return null }
|
||||
local sentinel_val = Scan.read_value_int_after(s, kt)
|
||||
// Safety check: must be valid numeric string
|
||||
if sentinel_val == null { return null }
|
||||
local sval_str = "" + sentinel_val
|
||||
if sval_str.length() == 0 { return null }
|
||||
if sval_str.length() > 10 { return null }
|
||||
// Must be numeric (basic check)
|
||||
local i = 0; local len = sval_str.length()
|
||||
loop(i < len) {
|
||||
local ch = sval_str.substring(i, i + 1)
|
||||
if ch < "0" || ch > "9" {
|
||||
if !(i == 0 && ch == "-") { return null }
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
return sentinel_val
|
||||
}
|
||||
// rhs が変数
|
||||
local kl = ("" + s).indexOf("\"lhs\":{", kcmp); if kl < 0 { return null }
|
||||
local kt2 = ("" + s).indexOf("\"type\":\"Int\"", kl); if kt2 < 0 { return null }
|
||||
local sentinel_val2 = Scan.read_value_int_after(s, kt2)
|
||||
// Safety check for rhs case
|
||||
if sentinel_val2 == null { return null }
|
||||
local sval_str2 = "" + sentinel_val2
|
||||
if sval_str2.length() == 0 { return null }
|
||||
if sval_str2.length() > 10 { return null }
|
||||
local i2 = 0; local len2 = sval_str2.length()
|
||||
loop(i2 < len2) {
|
||||
local ch2 = sval_str2.substring(i2, i2 + 1)
|
||||
if ch2 < "0" || ch2 > "9" {
|
||||
if !(i2 == 0 && ch2 == "-") { return null }
|
||||
}
|
||||
i2 = i2 + 1
|
||||
}
|
||||
return sentinel_val2
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user