feat(phase21.5/22.1): MirBuilder JsonFrag refactor + FileBox ring-1 + registry tests
Phase 21.5 (AOT/LLVM Optimization Prep) - FileBox ring-1 (core-ro) provider: priority=-100, always available, no panic path - src/runner/modes/common_util/provider_registry.rs: CoreRoFileProviderFactory - Auto-registers at startup, eliminates fallback panic structurally - StringBox fast path prototypes (length/size optimization) - Performance benchmarks (C/Python/Hako comparison baseline) Phase 22.1 (JsonFrag Unification) - JsonFrag.last_index_of_from() for backward search (VM fallback) - Replace hand-written lastIndexOf in lower_loop_sum_bc_box.hako - SentinelExtractorBox for Break/Continue pattern extraction MirBuilder Refactor (Box → JsonFrag Migration) - 20+ lower_*_box.hako: Box-heavy → JsonFrag text assembly - MirBuilderMinBox: lightweight using set for dev env - Registry-only fast path with [registry:*] tag observation - pattern_util_box.hako: enhanced pattern matching Dev Environment & Testing - Dev toggles: SMOKES_DEV_PREINCLUDE=1 (point-enable), HAKO_MIR_BUILDER_SKIP_LOOPS=1 - phase2160: registry opt-in tests (array/map get/set/push/len) - content verification - phase2034: rc-dependent → token grep (grep -F based validation) - run_quick.sh: fast smoke testing harness - ENV documentation: docs/ENV_VARS.md Test Results ✅ quick phase2034: ALL GREEN (MirBuilder internal patterns) ✅ registry phase2160: ALL GREEN (array/map get/set/push/len) ✅ rc-dependent tests → content token verification complete ✅ PREINCLUDE policy: default OFF, point-enable only where needed Technical Notes - No INCLUDE by default (maintain minimalism) - FAIL_FAST=0 in Bring-up contexts only (explicit dev toggles) - Tag-based route observation ([mirbuilder/min:*], [registry:*]) - MIR structure validation (not just rc parity) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -1,7 +1,16 @@
|
||||
// Stage-B compiler entry — ParserBox → FlowEntry emit-only
|
||||
// Notes (Dev/Doc):
|
||||
// - Scope: Hako だけで Program(JSON v0) を生成する自己ホスト入口。本文抽出→コメント除去→正規化→parse_program2 で一行JSONを出力。
|
||||
// - Robustness: 本文抽出は "method main" なしでも `box Main { main(...) { ... } }` からフォールバック抽出する。
|
||||
// 文字列を正しくスキップ(エスケープ対応)しつつ () と {} の対応を検出。// と /* */ のコメントは除去。
|
||||
// 前後の空白/改行もトリムして JSON 揺れを低減する。
|
||||
// - Known limits: VM の include は未対応。MirBuilder を VM 直で実行する経路は既定OFF(opt‑in検証のみ)。
|
||||
// - Policy: Program(JSON) → MIR(JSON) は Rust CLI 変換(Gate‑C)を既定とし、Hako ビルダーは opt‑in で段階導入する。
|
||||
// - Toggles around: HAKO_MIR_BUILDER_{INTERNAL,REGISTRY,DELEGATE}(MirBuilder側)。ここでは JSON 生成に専念する。
|
||||
// - Recommended: Dev/CI は wrapper(tools/hakorune_emit_mir.sh)経由で Program→MIR を行い、失敗時は Gate‑C に自動委譲する。
|
||||
|
||||
using sh_core as StringHelpers // Required: ParserStringUtilsBox depends on this (using chain unresolved)
|
||||
include "lang/src/compiler/entry/bundle_resolver.hako"
|
||||
using "hako.compiler.entry.bundle_resolver" as BundleResolver
|
||||
using lang.compiler.parser.box as ParserBox
|
||||
|
||||
// Note: Runner resolves entry as Main.main by default.
|
||||
@ -41,7 +50,7 @@ static box Main {
|
||||
{
|
||||
// naive search for "method main" → '(' → ')' → '{' ... balanced '}'
|
||||
local s = src
|
||||
// naive substring search for "method main"
|
||||
// naive substring search for "method main"; fallback to "main(" inside box Main
|
||||
local k0 = -1
|
||||
{
|
||||
local pat = "method main"
|
||||
@ -53,39 +62,127 @@ static box Main {
|
||||
i = i + 1
|
||||
}
|
||||
}
|
||||
if k0 < 0 {
|
||||
// Fallback: find "box Main" (with or without leading 'static') then locate "main(" after it
|
||||
local kbox = -1
|
||||
{
|
||||
local pat = "box Main"
|
||||
local m = pat.length()
|
||||
local i = 0
|
||||
local n = s.length()
|
||||
loop(i + m <= n) {
|
||||
if s.substring(i, i + m) == pat { kbox = i break }
|
||||
i = i + 1
|
||||
}
|
||||
}
|
||||
if kbox >= 0 {
|
||||
// search for "main(" starting at kbox
|
||||
local i = kbox
|
||||
local n = s.length()
|
||||
loop(i + 5 <= n) { // len("main(") = 5
|
||||
if s.substring(i, i + 5) == "main(" { k0 = i break }
|
||||
i = i + 1
|
||||
}
|
||||
} else {
|
||||
// last resort: global search of "main(" (may overmatch but better than full-file body)
|
||||
local i = 0
|
||||
local n = s.length()
|
||||
loop(i + 5 <= n) {
|
||||
if s.substring(i, i + 5) == "main(" { k0 = i break }
|
||||
i = i + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
if k0 >= 0 {
|
||||
// find '(' after k0
|
||||
// find '(' after k0 (skip inside strings)
|
||||
local k1 = -1
|
||||
{
|
||||
local j = k0
|
||||
local n = s.length()
|
||||
loop(j < n) { if s.substring(j, j + 1) == "(" { k1 = j break } j = j + 1 }
|
||||
local in_str = 0
|
||||
local esc = 0
|
||||
loop(j < n) {
|
||||
local ch = s.substring(j, j + 1)
|
||||
if in_str == 1 {
|
||||
if esc == 1 { esc = 0 j = j + 1 continue }
|
||||
if ch == "\\" { esc = 1 j = j + 1 continue }
|
||||
if ch == "\"" { in_str = 0 j = j + 1 continue }
|
||||
j = j + 1
|
||||
continue
|
||||
}
|
||||
if ch == "\"" { in_str = 1 j = j + 1 continue }
|
||||
if ch == "(" { k1 = j break }
|
||||
j = j + 1
|
||||
}
|
||||
}
|
||||
if k1 >= 0 {
|
||||
// find ')' after k1
|
||||
// find ')' after k1 (skip inside strings)
|
||||
local k2 = -1
|
||||
{
|
||||
local j = k1
|
||||
local n = s.length()
|
||||
loop(j < n) { if s.substring(j, j + 1) == ")" { k2 = j break } j = j + 1 }
|
||||
local in_str = 0
|
||||
local esc = 0
|
||||
loop(j < n) {
|
||||
local ch = s.substring(j, j + 1)
|
||||
if in_str == 1 {
|
||||
if esc == 1 { esc = 0 j = j + 1 continue }
|
||||
if ch == "\\" { esc = 1 j = j + 1 continue }
|
||||
if ch == "\"" { in_str = 0 j = j + 1 continue }
|
||||
j = j + 1
|
||||
continue
|
||||
}
|
||||
if ch == "\"" { in_str = 1 j = j + 1 continue }
|
||||
if ch == ")" { k2 = j break }
|
||||
j = j + 1
|
||||
}
|
||||
}
|
||||
if k2 >= 0 {
|
||||
// Find opening '{' following ')'
|
||||
// Find opening '{' following ')' (skip inside strings)
|
||||
local k3 = -1
|
||||
{
|
||||
local j = k2
|
||||
local n = s.length()
|
||||
loop(j < n) { if s.substring(j, j + 1) == "{" { k3 = j break } j = j + 1 }
|
||||
local in_str = 0
|
||||
local esc = 0
|
||||
loop(j < n) {
|
||||
local ch = s.substring(j, j + 1)
|
||||
if in_str == 1 {
|
||||
if esc == 1 { esc = 0 j = j + 1 continue }
|
||||
if ch == "\\" { esc = 1 j = j + 1 continue }
|
||||
if ch == "\"" { in_str = 0 j = j + 1 continue }
|
||||
j = j + 1
|
||||
continue
|
||||
}
|
||||
if ch == "\"" { in_str = 1 j = j + 1 continue }
|
||||
if ch == "{" { k3 = j break }
|
||||
j = j + 1
|
||||
}
|
||||
}
|
||||
if k3 >= 0 {
|
||||
// Balanced scan for matching '}'
|
||||
local depth = 0
|
||||
local i = k3
|
||||
local n = s.length()
|
||||
local in_str = 0
|
||||
local esc = 0
|
||||
loop(i < n) {
|
||||
local ch = s.substring(i, i + 1)
|
||||
if ch == "{" { depth = depth + 1 }
|
||||
else { if ch == "}" { depth = depth - 1 if depth == 0 { i = i + 1 break } } }
|
||||
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 == "{" { depth = depth + 1 i = i + 1 continue }
|
||||
if ch == "}" {
|
||||
depth = depth - 1
|
||||
i = i + 1
|
||||
if depth == 0 { break }
|
||||
continue
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
if depth == 0 {
|
||||
@ -100,6 +197,49 @@ static box Main {
|
||||
|
||||
if body_src == null { body_src = src }
|
||||
|
||||
// 4.7) Strip comments from body_src to avoid stray tokens in Program(JSON)
|
||||
{
|
||||
local s = body_src
|
||||
local out = ""
|
||||
local i = 0
|
||||
local n = s.length()
|
||||
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)
|
||||
if in_line == 1 {
|
||||
if ch == "\n" { in_line = 0 out = out + ch }
|
||||
i = i + 1
|
||||
continue
|
||||
}
|
||||
if in_block == 1 {
|
||||
if ch == "*" && i + 1 < n && s.substring(i + 1, i + 2) == "/" { in_block = 0 i = i + 2 continue }
|
||||
i = i + 1
|
||||
continue
|
||||
}
|
||||
if in_str == 1 {
|
||||
if esc == 1 { out = out + ch esc = 0 i = i + 1 continue }
|
||||
if ch == "\\" { out = out + ch esc = 1 i = i + 1 continue }
|
||||
if ch == "\"" { out = out + ch in_str = 0 i = i + 1 continue }
|
||||
out = out + ch
|
||||
i = i + 1
|
||||
continue
|
||||
}
|
||||
// Not in string/comment
|
||||
if ch == "\"" { out = out + 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 }
|
||||
}
|
||||
out = out + ch
|
||||
i = i + 1
|
||||
}
|
||||
body_src = out
|
||||
}
|
||||
|
||||
// 4.5) Optional: bundle extra module sources provided via repeated --bundle-src args
|
||||
// This is a minimal concatenation bundler (no I/O, no resolver). It simply places
|
||||
// provided module snippets before the main body for Stage‑B parser to accept.
|
||||
@ -176,7 +316,26 @@ static box Main {
|
||||
body_src = merged_prefix + body_src
|
||||
}
|
||||
|
||||
// 5) Parse and emit Stage‑1 JSON v0 (Program)
|
||||
// 5) Normalize body: trim leading/trailing whitespaces/newlines
|
||||
{
|
||||
local s = body_src
|
||||
local n = s.length()
|
||||
local b = 0
|
||||
// left trim (space, tab, CR, LF)
|
||||
loop(b < n) {
|
||||
local ch = s.substring(b, b + 1)
|
||||
if ch == " " || ch == "\t" || ch == "\r" || ch == "\n" { b = b + 1 } else { break }
|
||||
}
|
||||
// right trim
|
||||
local e = n
|
||||
loop(e > b) {
|
||||
local ch = s.substring(e - 1, e)
|
||||
if ch == " " || ch == "\t" || ch == "\r" || ch == "\n" { e = e - 1 } else { break }
|
||||
}
|
||||
if e > b { body_src = s.substring(b, e) } else { body_src = "" }
|
||||
}
|
||||
|
||||
// 6) Parse and emit Stage‑1 JSON v0 (Program)
|
||||
// Bridge(JSON v0) が Program v0 を受け取り MIR に lowering するため、ここでは AST(JSON v0) を出力する。
|
||||
// 既定で MIR 直出力は行わない(重い経路を避け、一行出力を保証)。
|
||||
local ast_json = p.parse_program2(body_src)
|
||||
|
||||
@ -14,6 +14,9 @@
|
||||
//
|
||||
// Phase 22.0: Hako‑first(registry)を既定ONにする。必要なら 0 を明示して無効化する。
|
||||
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
using "hako.mir.builder.internal.pattern_util" as PatternUtilBox
|
||||
|
||||
static box MirBuilderBox {
|
||||
// Availability probe (for canaries)
|
||||
is_available() {
|
||||
@ -47,7 +50,50 @@ static box MirBuilderBox {
|
||||
local use_reg = env.get("HAKO_MIR_BUILDER_REGISTRY")
|
||||
local reg_on = (use_reg == null) || (("" + use_reg) == "1")
|
||||
if reg_on == 1 {
|
||||
// Registry list
|
||||
// Optional: restrict registry candidates to a single name for bring-up
|
||||
local only = env.get("HAKO_MIR_BUILDER_REGISTRY_ONLY")
|
||||
// Fast path: registry-only=arraymap → 最小JsonFrag実装(heavy using を回避)
|
||||
if only != null && ("" + only) == "return.method.arraymap" {
|
||||
// Minimal inline lower (Return(Method Var recv, method, args...)) → mir_call(JSON文字列)
|
||||
// Scope: method in {get,set,push,length,size,len}(argsは最大2;Intのみ許容)
|
||||
local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0); if k_ret < 0 { return null }
|
||||
local k_m = JsonFragBox.index_of_from(s, "\"type\":\"Method\"", k_ret); if k_m < 0 { return null }
|
||||
local k_recv = JsonFragBox.index_of_from(s, "\"recv\":{\"type\":\"Var\"", k_m); if k_recv < 0 { return null }
|
||||
local k_mm = JsonFragBox.index_of_from(s, "\"method\":\"", k_m); if k_mm < 0 { return null }
|
||||
local method = JsonFragBox.read_string_after(s, k_mm + 9); if method == null { return null }
|
||||
// allow aliases
|
||||
if method == "len" { method = "length" }
|
||||
// build insts: receiver placeholder const 0 → r1
|
||||
local insts = "{\\\"op\\\":\\\"const\\\",\\\"dst\\\":1,\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":0}}"
|
||||
// parse up to two Int args
|
||||
local args_text = ""; local next_id = 2; local first = 1
|
||||
local k_args = JsonFragBox.index_of_from(s, "\"args\":", k_m)
|
||||
if k_args >= 0 {
|
||||
// first Int
|
||||
local k_i1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_args)
|
||||
if k_i1 >= 0 {
|
||||
local kv1 = JsonFragBox.index_of_from(s, "\"value\":", k_i1); if kv1 >= 0 {
|
||||
local v1 = JsonFragBox.read_int_after(s, kv1 + 8)
|
||||
if v1 != null { insts = insts + ",{\\\"op\\\":\\\"const\\\",\\\"dst\\\":" + next_id + ",\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":" + v1 + "}}"; args_text = args_text + ("" + next_id); next_id = next_id + 1; first = 0 }
|
||||
}
|
||||
}
|
||||
// second Int
|
||||
local k_i2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_args + 1)
|
||||
if k_i2 >= 0 {
|
||||
local kv2 = JsonFragBox.index_of_from(s, "\"value\":", k_i2); if kv2 >= 0 {
|
||||
local v2 = JsonFragBox.read_int_after(s, kv2 + 8)
|
||||
if v2 != null { insts = insts + ",{\\\"op\\\":\\\"const\\\",\\\"dst\\\":" + next_id + ",\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":" + v2 + "}}"; if first==0 { args_text = args_text + "," } ; args_text = args_text + ("" + next_id) }
|
||||
}
|
||||
}
|
||||
}
|
||||
local mir = "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[{\"name\":\"main\",\"blocks\":[{\"id\":0,\"instructions\":[" +
|
||||
insts + "," +
|
||||
"{\\\"op\\\":\\\"mir_call\\\",\\\"dst\\\":4,\\\"mir_call\\\":{\\\"callee\\\":{\\\"type\\\":\\\"Method\\\",\\\"method\\\":\\\"" + method + "\\\",\\\"receiver\\\":1},\\\"args\\\":[" + args_text + "],\\\"effects\\\":[]}}," +
|
||||
"{\\\"op\\\":\\\"ret\\\",\\\"value\\\":4}]}]}]}"
|
||||
print("[mirbuilder/registry:return.method.arraymap]")
|
||||
return mir
|
||||
}
|
||||
// Registry list(汎用)
|
||||
using "hako.mir.builder.pattern_registry" as PatternRegistryBox
|
||||
// Lowers needed by registry dispatch(using は prelude で集約される)
|
||||
using "hako.mir.builder.internal.lower_if_compare" as LowerIfCompareBox
|
||||
@ -56,6 +102,7 @@ static box MirBuilderBox {
|
||||
using "hako.mir.builder.internal.lower_if_compare_varint" as LowerIfCompareVarIntBox
|
||||
using "hako.mir.builder.internal.lower_if_compare_varvar" as LowerIfCompareVarVarBox
|
||||
using "hako.mir.builder.internal.lower_return_method_array_map" as LowerReturnMethodArrayMapBox
|
||||
using "hako.mir.builder.internal.lower_return_method_string_length" as LowerReturnMethodStringLengthBox
|
||||
using "hako.mir.builder.internal.lower_return_var_local" as LowerReturnVarLocalBox
|
||||
using "hako.mir.builder.internal.lower_return_string" as LowerReturnStringBox
|
||||
using "hako.mir.builder.internal.lower_return_float" as LowerReturnFloatBox
|
||||
@ -65,7 +112,10 @@ static box MirBuilderBox {
|
||||
using "hako.mir.builder.internal.lower_return_binop_varvar" as LowerReturnBinOpVarVarBox
|
||||
using "hako.mir.builder.internal.lower_return_binop" as LowerReturnBinOpBox
|
||||
using "hako.mir.builder.internal.lower_return_int" as LowerReturnIntBox
|
||||
using "hako.mir.builder.internal.lower_return_loop_strlen_sum" as LowerReturnLoopStrlenSumBox
|
||||
// Registry list(通常)
|
||||
local names = PatternRegistryBox.candidates()
|
||||
if only != null { local arr = new ArrayBox(); arr.push("" + only); names = arr }
|
||||
local i = 0; local n = names.length()
|
||||
loop(i < n) {
|
||||
local nm = "" + names.get(i)
|
||||
@ -75,6 +125,8 @@ static box MirBuilderBox {
|
||||
if nm == "if.compare.varint" { local out = LowerIfCompareVarIntBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "if.compare.varvar" { local out = LowerIfCompareVarVarBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "return.method.arraymap" { local out = LowerReturnMethodArrayMapBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "return.method.string.length" { local out = LowerReturnMethodStringLengthBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "return.loop.strlen.sum" { local out = LowerReturnLoopStrlenSumBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "return.var.local" { local out = LowerReturnVarLocalBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "return.string" { local out = LowerReturnStringBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "return.float" { local out = LowerReturnFloatBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
@ -114,7 +166,14 @@ static box MirBuilderBox {
|
||||
{ local out_toc = LowerTypeOpCheckBox.try_lower(s); if out_toc != null { return out_toc } }
|
||||
{ local out_tca = LowerTypeOpCastBox.try_lower(s); if out_tca != null { return out_tca } }
|
||||
// Loop lowers (sum_bc/continue/break normalization)
|
||||
{ local out_loop2 = LowerLoopSumBcBox.try_lower(s); if out_loop2 != null { return out_loop2 } }
|
||||
// Allow skipping heavy loop lowers on plugin-less hosts: HAKO_MIR_BUILDER_SKIP_LOOPS=1
|
||||
{
|
||||
local skip_loops = env.get("HAKO_MIR_BUILDER_SKIP_LOOPS")
|
||||
local do_loops = (skip_loops == null) || (("" + skip_loops) != "1")
|
||||
if do_loops == 1 {
|
||||
{ local out_loop2 = LowerLoopSumBcBox.try_lower(s); if out_loop2 != null { return out_loop2 } }
|
||||
}
|
||||
}
|
||||
{ local out_if2b = LowerIfNestedBox.try_lower(s); if out_if2b != null { return out_if2b } }
|
||||
{ local out_if2 = LowerIfThenElseFollowingReturnBox.try_lower(s); if out_if2 != null { return out_if2 } }
|
||||
{ local out_if = LowerIfCompareBox.try_lower(s); if out_if != null { return out_if } }
|
||||
@ -122,13 +181,21 @@ static box MirBuilderBox {
|
||||
{ local out_ifbv = LowerIfCompareFoldVarIntBox.try_lower(s); if out_ifbv != null { return out_ifbv } }
|
||||
{ local out_ifvi = LowerIfCompareVarIntBox.try_lower(s); if out_ifvi != null { return out_ifvi } }
|
||||
{ local out_ifvv = LowerIfCompareVarVarBox.try_lower(s); if out_ifvv != null { return out_ifvv } }
|
||||
{ local out_loopp = LowerLoopCountParamBox.try_lower(s); if out_loopp != null { return out_loopp } }
|
||||
{ local out_loop = LowerLoopSimpleBox.try_lower(s); if out_loop != null { return out_loop } }
|
||||
{
|
||||
local skip_loops2 = env.get("HAKO_MIR_BUILDER_SKIP_LOOPS")
|
||||
local do_loops2 = (skip_loops2 == null) || (("" + skip_loops2) != "1")
|
||||
if do_loops2 == 1 {
|
||||
{ local out_loopp = LowerLoopCountParamBox.try_lower(s); if out_loopp != null { return out_loopp } }
|
||||
{ local out_loop = LowerLoopSimpleBox.try_lower(s); if out_loop != null { return out_loop } }
|
||||
}
|
||||
}
|
||||
{ local out_var = LowerReturnVarLocalBox.try_lower(s); if out_var != null { return out_var } }
|
||||
{ local out_str = LowerReturnStringBox.try_lower(s); if out_str != null { return out_str } }
|
||||
{ local out_f = LowerReturnFloatBox.try_lower(s); if out_f != null { return out_f } }
|
||||
{ local out_log = LowerReturnLogicalBox.try_lower(s); if out_log != null { return out_log } }
|
||||
{ local out_meth = LowerReturnMethodArrayMapBox.try_lower(s); if out_meth != null { return out_meth } }
|
||||
{ local out_meth_s = LowerReturnMethodStringLengthBox.try_lower(s); if out_meth_s != null { return out_meth_s } }
|
||||
{ local out_sum = LowerReturnLoopStrlenSumBox.try_lower(s); if out_sum != null { return out_sum } }
|
||||
{ local out_bool = LowerReturnBoolBox.try_lower(s); if out_bool != null { return out_bool } }
|
||||
{ local out_bvi = LowerReturnBinOpVarIntBox.try_lower(s); if out_bvi != null { return out_bvi } }
|
||||
{ local out_bvv = LowerReturnBinOpVarVarBox.try_lower(s); if out_bvv != null { return out_bvv } }
|
||||
@ -140,19 +207,15 @@ static box MirBuilderBox {
|
||||
// Find Return marker (or If)
|
||||
// Case (If with Compare + Return(Int)/Return(Int) in branches)
|
||||
{
|
||||
local k_if = s.indexOf("\"type\":\"If\"")
|
||||
local k_if = JsonFragBox.index_of_from(s, "\"type\":\"If\"", 0)
|
||||
if k_if >= 0 {
|
||||
// cond: Compare with Int lhs/rhs
|
||||
local k_cmp = s.indexOf("\"type\":\"Compare\"", k_if)
|
||||
local k_cmp = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", k_if)
|
||||
if k_cmp >= 0 {
|
||||
// op
|
||||
local k_op2 = s.indexOf("\"op\":", k_cmp)
|
||||
local k_op2 = JsonFragBox.index_of_from(s, "\"op\":", k_cmp)
|
||||
if k_op2 >= 0 {
|
||||
local oi2 = k_op2 + 5; local on2 = s.length()
|
||||
loop(oi2 < on2) { local ch = s.substring(oi2,oi2+1); if ch == "\"" { oi2 = oi2 + 1 break } if ch != " " { break } oi2 = oi2 + 1 }
|
||||
local oj2 = oi2
|
||||
loop(oj2 < on2) { local ch2 = s.substring(oj2,oj2+1); if ch2 == "\"" { break } oj2 = oj2 + 1 }
|
||||
local op2 = s.substring(oi2, oj2)
|
||||
local op2 = JsonFragBox.read_string_after(s, k_op2 + 5)
|
||||
// support <,>,<=,>=,==,!=
|
||||
if !(op2 == "<" || op2 == ">" || op2 == "<=" || op2 == ">=" || op2 == "==" || op2 == "!=") {
|
||||
print("[mirbuilder/internal/unsupported] compare op: " + op2)
|
||||
@ -161,18 +224,13 @@ static box MirBuilderBox {
|
||||
// lhs Int
|
||||
local lhs_val2 = null
|
||||
{
|
||||
local klhs2 = s.indexOf("\"lhs\":{", k_cmp)
|
||||
local klhs2 = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp)
|
||||
if klhs2 >= 0 {
|
||||
local ti = s.indexOf("\"type\":\"Int\"", klhs2)
|
||||
local ti = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", klhs2)
|
||||
if ti >= 0 {
|
||||
local kv = s.indexOf("\"value\":", ti)
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", ti)
|
||||
if kv >= 0 {
|
||||
local i = kv + 8; local n = s.length();
|
||||
loop(i < n) { if s.substring(i,i+1) != " " { break } i = i + 1 }
|
||||
local j = i; if j < n && s.substring(j,j+1) == "-" { j = j + 1 }
|
||||
local had = 0
|
||||
loop(j < n) { local ch = s.substring(j,j+1); if ch >= "0" && ch <= "9" { had = 1 j = j + 1 } else { break } }
|
||||
if had == 1 { lhs_val2 = s.substring(i,j) }
|
||||
lhs_val2 = JsonFragBox.read_int_after(s, kv + 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -180,62 +238,49 @@ static box MirBuilderBox {
|
||||
// rhs Int
|
||||
local rhs_val2 = null
|
||||
{
|
||||
local krhs2 = s.indexOf("\"rhs\":{", k_cmp)
|
||||
local krhs2 = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp)
|
||||
if krhs2 >= 0 {
|
||||
local ti = s.indexOf("\"type\":\"Int\"", krhs2)
|
||||
local ti = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", krhs2)
|
||||
if ti >= 0 {
|
||||
local kv = s.indexOf("\"value\":", ti)
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", ti)
|
||||
if kv >= 0 {
|
||||
local i = kv + 8; local n = s.length();
|
||||
loop(i < n) { if s.substring(i,i+1) != " " { break } i = i + 1 }
|
||||
local j = i; if j < n && s.substring(j,j+1) == "-" { j = j + 1 }
|
||||
local had = 0
|
||||
loop(j < n) { local ch = s.substring(j,j+1); if ch >= "0" && ch <= "9" { had = 1 j = j + 1 } else { break } }
|
||||
if had == 1 { rhs_val2 = s.substring(i,j) }
|
||||
rhs_val2 = JsonFragBox.read_int_after(s, kv + 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// then: Return(Int ...)
|
||||
// then: Return(Int ...) — limit search to then array bounds
|
||||
local then_val = null
|
||||
{
|
||||
local kth = s.indexOf("\"then\":", k_if)
|
||||
if kth >= 0 {
|
||||
local rt = s.indexOf("\"type\":\"Return\"", kth)
|
||||
if rt >= 0 {
|
||||
local ti = s.indexOf("\"type\":\"Int\"", rt)
|
||||
if ti >= 0 {
|
||||
local kv = s.indexOf("\"value\":", ti)
|
||||
if kv >= 0 {
|
||||
local i = kv + 8; local n = s.length();
|
||||
loop(i < n) { if s.substring(i,i+1) != " " { break } i = i + 1 }
|
||||
local j = i; if j < n && s.substring(j,j+1) == "-" { j = j + 1 }
|
||||
local had = 0
|
||||
loop(j < n) { local ch = s.substring(j,j+1); if ch >= "0" && ch <= "9" { had = 1 j = j + 1 } else { break } }
|
||||
if had == 1 { then_val = s.substring(i,j) }
|
||||
}
|
||||
local tb = PatternUtilBox.then_array_bounds(s, k_if)
|
||||
if tb != null {
|
||||
local cp = tb.indexOf(":")
|
||||
if cp >= 0 {
|
||||
local lb_then = JsonFragBox._str_to_int(tb.substring(0, cp))
|
||||
local rb_then = JsonFragBox._str_to_int(tb.substring(cp + 1, tb.length()))
|
||||
local rt = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", lb_then)
|
||||
if rt >= 0 && rt < rb_then {
|
||||
local ti = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt)
|
||||
if ti >= 0 && ti < rb_then {
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", ti)
|
||||
if kv >= 0 && kv < rb_then { then_val = JsonFragBox.read_int_after(s, kv + 8) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// else: Return(Int ...)
|
||||
// else: Return(Int ...) — limit to else array bounds
|
||||
local else_val = null
|
||||
{
|
||||
local kel = s.indexOf("\"else\":", k_if)
|
||||
if kel >= 0 {
|
||||
local rt = s.indexOf("\"type\":\"Return\"", kel)
|
||||
if rt >= 0 {
|
||||
local ti = s.indexOf("\"type\":\"Int\"", rt)
|
||||
if ti >= 0 {
|
||||
local kv = s.indexOf("\"value\":", ti)
|
||||
if kv >= 0 {
|
||||
local i = kv + 8; local n = s.length();
|
||||
loop(i < n) { if s.substring(i,i+1) != " " { break } i = i + 1 }
|
||||
local j = i; if j < n && s.substring(j,j+1) == "-" { j = j + 1 }
|
||||
local had = 0
|
||||
loop(j < n) { local ch = s.substring(j,j+1); if ch >= "0" && ch <= "9" { had = 1 j = j + 1 } else { break } }
|
||||
if had == 1 { else_val = s.substring(i,j) }
|
||||
}
|
||||
local eb = PatternUtilBox.else_array_bounds_after_then(s, k_if)
|
||||
if eb != null {
|
||||
local cp2 = eb.indexOf(":")
|
||||
if cp2 >= 0 {
|
||||
local lb_else = JsonFragBox._str_to_int(eb.substring(0, cp2))
|
||||
local rb_else = JsonFragBox._str_to_int(eb.substring(cp2 + 1, eb.length()))
|
||||
local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", lb_else)
|
||||
if rt2 >= 0 && rt2 < rb_else {
|
||||
local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2)
|
||||
if ti2 >= 0 && ti2 < rb_else {
|
||||
local kv2 = JsonFragBox.index_of_from(s, "\"value\":", ti2)
|
||||
if kv2 >= 0 && kv2 < rb_else { else_val = JsonFragBox.read_int_after(s, kv2 + 8) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -261,55 +306,37 @@ static box MirBuilderBox {
|
||||
if out_new != null { return out_new }
|
||||
}
|
||||
// Fallback cases below: Return(Binary) and Return(Int)
|
||||
local k_ret = s.indexOf("\"type\":\"Return\"")
|
||||
local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0)
|
||||
if k_ret >= 0 {
|
||||
// Case (Binary): {"type":"Binary","op":"+|-|*|/","lhs":{Int},"rhs":{Int}}
|
||||
local k_bin = s.indexOf("\"type\":\"Binary\"", k_ret)
|
||||
local k_bin = JsonFragBox.index_of_from(s, "\"type\":\"Binary\"", k_ret)
|
||||
if k_bin >= 0 {
|
||||
// op
|
||||
local k_op = s.indexOf("\"op\":", k_bin)
|
||||
local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_bin)
|
||||
if k_op >= 0 {
|
||||
local oi = k_op + 5; local on = s.length()
|
||||
loop(oi < on) { local ch = s.substring(oi,oi+1); if ch == "\"" { oi = oi + 1 break } if ch != " " { break } oi = oi + 1 }
|
||||
local oj = oi
|
||||
loop(oj < on) { local ch2 = s.substring(oj,oj+1); if ch2 == "\"" { break } oj = oj + 1 }
|
||||
local op = s.substring(oi, oj)
|
||||
local op = JsonFragBox.read_string_after(s, k_op + 5)
|
||||
if !(op == "+" || op == "-" || op == "*" || op == "/") {
|
||||
print("[mirbuilder/internal/unsupported] binary op: " + op)
|
||||
return null
|
||||
}
|
||||
// lhs Int value
|
||||
local klhs = s.indexOf("\"lhs\":{", k_bin)
|
||||
local klhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_bin)
|
||||
local lhs_val = null
|
||||
if klhs >= 0 {
|
||||
local ti = s.indexOf("\"type\":\"Int\"", klhs)
|
||||
local ti = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", klhs)
|
||||
if ti >= 0 {
|
||||
local kv = s.indexOf("\"value\":", ti)
|
||||
if kv >= 0 {
|
||||
local i = kv + 8; local n = s.length();
|
||||
loop(i < n) { if s.substring(i,i+1) != " " { break } i = i + 1 }
|
||||
local j = i; if j < n && s.substring(j,j+1) == "-" { j = j + 1 }
|
||||
local had = 0
|
||||
loop(j < n) { local ch = s.substring(j,j+1); if ch >= "0" && ch <= "9" { had = 1 j = j + 1 } else { break } }
|
||||
if had == 1 { lhs_val = s.substring(i,j) }
|
||||
}
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", ti)
|
||||
if kv >= 0 { lhs_val = JsonFragBox.read_int_after(s, kv + 8) }
|
||||
}
|
||||
}
|
||||
// rhs Int value
|
||||
local krhs = s.indexOf("\"rhs\":{", k_bin)
|
||||
local krhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_bin)
|
||||
local rhs_val = null
|
||||
if krhs >= 0 {
|
||||
local ti2 = s.indexOf("\"type\":\"Int\"", krhs)
|
||||
local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", krhs)
|
||||
if ti2 >= 0 {
|
||||
local kv2 = s.indexOf("\"value\":", ti2)
|
||||
if kv2 >= 0 {
|
||||
local i2 = kv2 + 8; local n2 = s.length();
|
||||
loop(i2 < n2) { if s.substring(i2,i2+1) != " " { break } i2 = i2 + 1 }
|
||||
local j2 = i2; if j2 < n2 && s.substring(j2,j2+1) == "-" { j2 = j2 + 1 }
|
||||
local had2 = 0
|
||||
loop(j2 < n2) { local ch3 = s.substring(j2,j2+1); if ch3 >= "0" && ch3 <= "9" { had2 = 1 j2 = j2 + 1 } else { break } }
|
||||
if had2 == 1 { rhs_val = s.substring(i2,j2) }
|
||||
}
|
||||
local kv2 = JsonFragBox.index_of_from(s, "\"value\":", ti2)
|
||||
if kv2 >= 0 { rhs_val = JsonFragBox.read_int_after(s, kv2 + 8) }
|
||||
}
|
||||
}
|
||||
if lhs_val != null && rhs_val != null {
|
||||
@ -323,50 +350,23 @@ static box MirBuilderBox {
|
||||
}
|
||||
}
|
||||
// Case (Int): Return(Int N) — ensure expr.type is Int (not Binary/Logical/etc)
|
||||
local k_expr = s.indexOf("\"expr\":{", k_ret)
|
||||
local k_expr = JsonFragBox.index_of_from(s, "\"expr\":{", k_ret)
|
||||
if k_expr >= 0 {
|
||||
// Check direct type after "expr":{
|
||||
local k_type_start = k_expr + 8
|
||||
local k_type = s.indexOf("\"type\":", k_type_start)
|
||||
if k_type >= 0 && k_type < k_type_start + 20 {
|
||||
// Extract the type value
|
||||
local k_type_val = k_type + 7
|
||||
local n = s.length()
|
||||
loop(k_type_val < n) { if s.substring(k_type_val, k_type_val+1) != " " && s.substring(k_type_val, k_type_val+1) != "\"" { break } k_type_val = k_type_val + 1 }
|
||||
// Check if it's "Int" (not "Binary", "Logical", "Var", etc)
|
||||
local is_int_type = 0
|
||||
if k_type_val + 3 <= n {
|
||||
if s.substring(k_type_val, k_type_val+3) == "Int" {
|
||||
// Verify it's followed by quote (not "Integer" or other extension)
|
||||
if k_type_val + 3 < n && s.substring(k_type_val+3, k_type_val+4) == "\"" {
|
||||
is_int_type = 1
|
||||
}
|
||||
// Quick check for Int near expr
|
||||
local kt = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_expr)
|
||||
if kt >= 0 && kt < k_expr + 64 {
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", kt)
|
||||
if kv >= 0 {
|
||||
local num = JsonFragBox.read_int_after(s, kv + 8)
|
||||
if num != null {
|
||||
if env.get("HAKO_MIR_BUILDER_DEBUG") == "1" || env.get("NYASH_CLI_VERBOSE") == "1" { print("[mirbuilder/fallback:Return(Int) val=" + num + "]") }
|
||||
local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[{\"id\":0,\"instructions\":[{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + num + "}},{\"op\":\"ret\",\"value\":1}]}]}]}"
|
||||
return mir
|
||||
}
|
||||
}
|
||||
if is_int_type == 1 {
|
||||
local debug_on = 0
|
||||
if env.get("HAKO_MIR_BUILDER_DEBUG") == "1" || env.get("NYASH_CLI_VERBOSE") == "1" { debug_on = 1 }
|
||||
local k_expr_int = s.indexOf("\"type\":\"Int\"", k_expr)
|
||||
local k_val = s.indexOf("\"value\":", k_expr_int)
|
||||
if k_val >= 0 {
|
||||
local i = k_val + 8
|
||||
loop(i < n) { if s.substring(i,i+1) != " " { break } i = i + 1 }
|
||||
local j = i
|
||||
if j < n && s.substring(j,j+1) == "-" { j = j + 1 }
|
||||
local had = 0
|
||||
loop(j < n) { local ch = s.substring(j,j+1); if ch >= "0" && ch <= "9" { had = 1 j = j + 1 } else { break } }
|
||||
if had == 1 {
|
||||
local num = s.substring(i, j)
|
||||
if debug_on == 1 { print("[mirbuilder/fallback:Return(Int) val=" + num + "]") }
|
||||
local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[{\"id\":0,\"instructions\":[{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + num + "}},{\"op\":\"ret\",\"value\":1}]}]}]}"
|
||||
return mir
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// expr.type is not Int (e.g. Binary) - don't match this fallback
|
||||
if env.get("HAKO_MIR_BUILDER_DEBUG") == "1" || env.get("NYASH_CLI_VERBOSE") == "1" {
|
||||
print("[mirbuilder/fallback:Return(Int) skip - expr.type not Int]")
|
||||
}
|
||||
} else {
|
||||
if env.get("HAKO_MIR_BUILDER_DEBUG") == "1" || env.get("NYASH_CLI_VERBOSE") == "1" {
|
||||
print("[mirbuilder/fallback:Return(Int) skip - expr.type not Int]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
38
lang/src/mir/builder/MirBuilderMinBox.hako
Normal file
38
lang/src/mir/builder/MirBuilderMinBox.hako
Normal file
@ -0,0 +1,38 @@
|
||||
// MirBuilderMinBox — Minimal Program(JSON v0) → MIR(JSON) for opt-in bring-up
|
||||
// Scope: small set of lowers only(軽量usingでVM実行を安定化)
|
||||
// Toggles: なし(この箱自体は最小/静的)。
|
||||
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
using "hako.mir.builder.internal.lower_return_method_array_map" as LowerReturnMethodArrayMapBox
|
||||
using "hako.mir.builder.internal.lower_return_int" as LowerReturnIntBox
|
||||
using "hako.mir.builder.internal.lower_return_binop" as LowerReturnBinOpBox
|
||||
using "hako.mir.builder.internal.lower_return_binop_varint" as LowerReturnBinOpVarIntBox
|
||||
using "hako.mir.builder.internal.lower_if_compare" as LowerIfCompareBox
|
||||
using "hako.mir.builder.internal.lower_if_compare_fold_varint" as LowerIfCompareFoldVarIntBox
|
||||
using "hako.mir.builder.internal.lower_if_compare_fold_binints" as LowerIfCompareFoldBinIntsBox
|
||||
using "hako.mir.builder.internal.lower_return_binop_varvar" as LowerReturnBinOpVarVarBox
|
||||
using "hako.mir.builder.internal.lower_if_compare_varint" as LowerIfCompareVarIntBox
|
||||
using "hako.mir.builder.internal.lower_if_compare_varvar" as LowerIfCompareVarVarBox
|
||||
|
||||
static box MirBuilderBox {
|
||||
// Minimal entry
|
||||
method emit_from_program_json_v0(program_json, opts) {
|
||||
if program_json == null { print("[mirbuilder/min/input:null]"); return null }
|
||||
local s = "" + program_json
|
||||
if !(s.contains("\"version\"")) || !(s.contains("\"kind\"")) { print("[mirbuilder/min/input:invalid]"); return null }
|
||||
// Try minimal patterns (lightweight only)
|
||||
{ local out = LowerReturnMethodArrayMapBox.try_lower(s); if out != null { print("[mirbuilder/min:return.method.arraymap]"); return out } }
|
||||
{ local out_v = LowerReturnBinOpVarIntBox.try_lower(s); if out_v != null { print("[mirbuilder/min:return.binop.varint]"); return out_v } }
|
||||
{ local out_b = LowerReturnBinOpBox.try_lower(s); if out_b != null { print("[mirbuilder/min:return.binop.intint]"); return out_b } }
|
||||
{ local out_bvv = LowerReturnBinOpVarVarBox.try_lower(s); if out_bvv != null { print("[mirbuilder/min:return.binop.varvar]"); return out_bvv } }
|
||||
// Compare lowers: prefer fold/var-based before int-int to avoid greedy match
|
||||
{ local out_if_fv = LowerIfCompareFoldVarIntBox.try_lower(s); if out_if_fv != null { print("[mirbuilder/min:if.compare.fold.varint]"); return out_if_fv } }
|
||||
{ local out_if_fb = LowerIfCompareFoldBinIntsBox.try_lower(s); if out_if_fb != null { print("[mirbuilder/min:if.compare.fold.binints]"); return out_if_fb } }
|
||||
{ local out_ifvi = LowerIfCompareVarIntBox.try_lower(s); if out_ifvi != null { print("[mirbuilder/min:if.compare.varint]"); return out_ifvi } }
|
||||
{ local out_ifvv = LowerIfCompareVarVarBox.try_lower(s); if out_ifvv != null { print("[mirbuilder/min:if.compare.varvar]"); return out_ifvv } }
|
||||
{ local out_if = LowerIfCompareBox.try_lower(s); if out_if != null { print("[mirbuilder/min:if.compare.intint]"); return out_if } }
|
||||
{ local out2 = LowerReturnIntBox.try_lower(s); if out2 != null { print("[mirbuilder/min:return.int]"); return out2 } }
|
||||
print("[mirbuilder/min/unsupported]")
|
||||
return null
|
||||
}
|
||||
}
|
||||
@ -6,13 +6,15 @@ 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 {
|
||||
local kn = ("" + s).indexOf("\"name\":\"", kl); if kn >= 0 { varname = JsonFragBox.read_string_after(s, kn) }
|
||||
local kl = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp)
|
||||
local kr = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp)
|
||||
if kl >= 0 && JsonFragBox.index_of_from(s, "\"type\":\"Var\"", kl) >= 0 {
|
||||
local kn = JsonFragBox.index_of_from(s, "\"name\":\"", kl)
|
||||
if kn >= 0 { varname = JsonFragBox.read_string_after(s, kn) }
|
||||
}
|
||||
if varname == null && kr >= 0 && ("" + s).indexOf("\"type\":\"Var\"", kr) >= 0 {
|
||||
local kn2 = ("" + s).indexOf("\"name\":\"", kr); if kn2 >= 0 { varname = JsonFragBox.read_string_after(s, kn2) }
|
||||
if varname == null && kr >= 0 && JsonFragBox.index_of_from(s, "\"type\":\"Var\"", kr) >= 0 {
|
||||
local kn2 = JsonFragBox.index_of_from(s, "\"name\":\"", kr)
|
||||
if kn2 >= 0 { varname = JsonFragBox.read_string_after(s, kn2) }
|
||||
}
|
||||
return varname
|
||||
}
|
||||
@ -21,14 +23,14 @@ static box LoopScanBox {
|
||||
// sentinel: "Break" | "Continue"
|
||||
extract_ne_else_sentinel_value(s, sentinel, k_loop, varname) {
|
||||
local st = "\"type\":\"" + sentinel + "\""
|
||||
local ks = ("" + s).indexOf(st, k_loop)
|
||||
local ks = JsonFragBox.index_of_from(s, st, k_loop)
|
||||
if ks < 0 { return null }
|
||||
// 直前の If と Compare を見つける(同一 then/else 内の近傍に限定)
|
||||
local kif = ("" + s).lastIndexOf("\"type\":\"If\"", ks)
|
||||
local kif = JsonFragBox.last_index_of_from(s, "\"type\":\"If\"", ks)
|
||||
if kif < 0 { return null }
|
||||
local kcmp = ("" + s).lastIndexOf("\"type\":\"Compare\"", ks)
|
||||
local kcmp = JsonFragBox.last_index_of_from(s, "\"type\":\"Compare\"", ks)
|
||||
if kcmp < 0 || kcmp < kif { return null }
|
||||
local kop = ("" + s).indexOf("\"op\":", kcmp); if kop < 0 { return null }
|
||||
local kop = JsonFragBox.index_of_from(s, "\"op\":", kcmp); if kop < 0 { return null }
|
||||
local op = JsonFragBox.read_string_after(s, kop + 5); if op == null || op != "!=" { return null }
|
||||
// else 範囲の配列区間を特定
|
||||
local kth = JsonFragBox.index_of_from(s, "\"then\":", kif); if kth < 0 { return null }
|
||||
@ -40,13 +42,13 @@ static box LoopScanBox {
|
||||
// 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
|
||||
local has_lhs = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kcmp) >= 0
|
||||
local has_rhs = JsonFragBox.index_of_from(s, "\"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 kv = ("" + s).indexOf("\"value\":", kt); if kv < 0 { return null }
|
||||
local kr = JsonFragBox.index_of_from(s, "\"rhs\":{", kcmp); if kr < 0 { return null }
|
||||
local kt = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", kr); if kt < 0 { return null }
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", kt); if kv < 0 { return null }
|
||||
local sentinel_val = JsonFragBox.read_int_after(s, kv + 8)
|
||||
// Safety check: must be valid numeric string
|
||||
if sentinel_val == null { return null }
|
||||
@ -65,9 +67,9 @@ static box LoopScanBox {
|
||||
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 kv2 = ("" + s).indexOf("\"value\":", kt2); if kv2 < 0 { return null }
|
||||
local kl = JsonFragBox.index_of_from(s, "\"lhs\":{", kcmp); if kl < 0 { return null }
|
||||
local kt2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", kl); if kt2 < 0 { return null }
|
||||
local kv2 = JsonFragBox.index_of_from(s, "\"value\":", kt2); if kv2 < 0 { return null }
|
||||
local sentinel_val2 = JsonFragBox.read_int_after(s, kv2 + 8)
|
||||
// Safety check for rhs case
|
||||
if sentinel_val2 == null { return null }
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// lower_if_compare_box.hako — If(Compare(Int,Int), then Return(Int), else Return(Int)) → compare+branch+ret×2
|
||||
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
using "hako.mir.builder.internal.pattern_util" as PatternUtilBox
|
||||
|
||||
static box LowerIfCompareBox {
|
||||
try_lower(program_json) {
|
||||
@ -32,27 +33,29 @@ static box LowerIfCompareBox {
|
||||
if kv_rhs < 0 { return null }
|
||||
local rhs_val = JsonFragBox.read_int_after(s, kv_rhs + 8)
|
||||
if rhs_val == null { return null }
|
||||
// then/else return ints
|
||||
local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if)
|
||||
if kth < 0 { return null }
|
||||
local rt = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth)
|
||||
if rt < 0 { return null }
|
||||
// then/else return ints (bounded within arrays)
|
||||
local tb = PatternUtilBox.then_array_bounds(s, k_if); if tb == null { return null }
|
||||
local cp = tb.indexOf(":"); if cp < 0 { return null }
|
||||
local lb_then = JsonFragBox._str_to_int(tb.substring(0, cp))
|
||||
local rb_then = JsonFragBox._str_to_int(tb.substring(cp + 1, tb.length()))
|
||||
local rt = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", lb_then)
|
||||
if rt < 0 || rt >= rb_then { return null }
|
||||
local ti3 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt)
|
||||
if ti3 < 0 { return null }
|
||||
if ti3 < 0 || ti3 >= rb_then { return null }
|
||||
local kv_then = JsonFragBox.index_of_from(s, "\"value\":", ti3)
|
||||
if kv_then < 0 { return null }
|
||||
local then_val = JsonFragBox.read_int_after(s, kv_then + 8)
|
||||
if then_val == null { return null }
|
||||
local kel = JsonFragBox.index_of_from(s, "\"else\":", k_if)
|
||||
if kel < 0 { return null }
|
||||
local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kel)
|
||||
if rt2 < 0 { return null }
|
||||
if kv_then < 0 || kv_then >= rb_then { return null }
|
||||
local then_val = JsonFragBox.read_int_after(s, kv_then + 8); if then_val == null { return null }
|
||||
local eb = PatternUtilBox.else_array_bounds_after_then(s, k_if); if eb == null { return null }
|
||||
local cp2 = eb.indexOf(":"); if cp2 < 0 { return null }
|
||||
local lb_else = JsonFragBox._str_to_int(eb.substring(0, cp2))
|
||||
local rb_else = JsonFragBox._str_to_int(eb.substring(cp2 + 1, eb.length()))
|
||||
local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", lb_else)
|
||||
if rt2 < 0 || rt2 >= rb_else { return null }
|
||||
local ti4 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2)
|
||||
if ti4 < 0 { return null }
|
||||
if ti4 < 0 || ti4 >= rb_else { return null }
|
||||
local kv_else = JsonFragBox.index_of_from(s, "\"value\":", ti4)
|
||||
if kv_else < 0 { return null }
|
||||
local else_val = JsonFragBox.read_int_after(s, kv_else + 8)
|
||||
if else_val == null { return null }
|
||||
if kv_else < 0 || kv_else >= rb_else { return null }
|
||||
local else_val = JsonFragBox.read_int_after(s, kv_else + 8); if else_val == null { return null }
|
||||
|
||||
// Emit MIR v0 JSON as string (functions[]/name="main"/blocks.id)
|
||||
local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[" +
|
||||
|
||||
@ -7,8 +7,9 @@ using selfhost.shared.mir.schema as MirSchemaBox
|
||||
static box LowerIfCompareFoldBinIntsBox {
|
||||
_fold_bin_ints(s, k_bin_start) {
|
||||
// expects: {"type":"Binary","op":"+|-|*|/","lhs":{"type":"Int","value":L},"rhs":{"type":"Int","value":R}}
|
||||
local kop = JsonFragBox.index_of_from(s, "\"op\":\"", k_bin_start); if kop < 0 { return null }
|
||||
local iop = kop + 6; local op = s.substring(iop, iop+1)
|
||||
local kop = JsonFragBox.index_of_from(s, "\"op\":", k_bin_start); if kop < 0 { return null }
|
||||
// read op string ("+"|"-"|"*"|"/") robustly
|
||||
local op = JsonFragBox.read_string_after(s, kop + 5)
|
||||
if !(op == "+" || op == "-" || op == "*" || op == "/") { return null }
|
||||
local kli = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_bin_start); if kli < 0 { return null }
|
||||
local kvl = JsonFragBox.index_of_from(s, "\"value\":", kli); if kvl < 0 { return null }
|
||||
@ -64,22 +65,31 @@ static box LowerIfCompareFoldBinIntsBox {
|
||||
local lhs_val = me._resolve_side_int(s, lhs_pos, k_if)
|
||||
local rhs_val = me._resolve_side_int(s, rhs_pos, k_if)
|
||||
if lhs_val == null || rhs_val == null { return null }
|
||||
// then/else Return(Int)
|
||||
local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if); if kth < 0 { return null }
|
||||
local rt1 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth); if rt1 < 0 { return null }
|
||||
local ti1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt1); if ti1 < 0 { return null }
|
||||
local kv1 = JsonFragBox.index_of_from(s, "\"value\":", ti1); if kv1 < 0 { return null }
|
||||
// then/else Return(Int) — boundary limited
|
||||
local tb = PatternUtilBox.then_array_bounds(s, k_if); if tb == null { return null }
|
||||
local cp = tb.indexOf(":"); if cp < 0 { return null }
|
||||
local lb_then = JsonFragBox._str_to_int(tb.substring(0, cp))
|
||||
local rb_then = JsonFragBox._str_to_int(tb.substring(cp + 1, tb.length()))
|
||||
local rt1 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", lb_then); if rt1 < 0 || rt1 >= rb_then { return null }
|
||||
local ti1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt1); if ti1 < 0 || ti1 >= rb_then { return null }
|
||||
local kv1 = JsonFragBox.index_of_from(s, "\"value\":", ti1); if kv1 < 0 || kv1 >= rb_then { return null }
|
||||
local then_v = JsonFragBox.read_int_after(s, kv1 + 8); if then_v == null { return null }
|
||||
local kel = JsonFragBox.index_of_from(s, "\"else\":", k_if); if kel < 0 { return null }
|
||||
local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kel); if rt2 < 0 { return null }
|
||||
local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2); if ti2 < 0 { return null }
|
||||
local kv2b = JsonFragBox.index_of_from(s, "\"value\":", ti2); if kv2b < 0 { return null }
|
||||
local eb = PatternUtilBox.else_array_bounds_after_then(s, k_if); if eb == null { return null }
|
||||
local cp2 = eb.indexOf(":"); if cp2 < 0 { return null }
|
||||
local lb_else = JsonFragBox._str_to_int(eb.substring(0, cp2))
|
||||
local rb_else = JsonFragBox._str_to_int(eb.substring(cp2 + 1, eb.length()))
|
||||
local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", lb_else); if rt2 < 0 || rt2 >= rb_else { return null }
|
||||
local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2); if ti2 < 0 || ti2 >= rb_else { return null }
|
||||
local kv2b = JsonFragBox.index_of_from(s, "\"value\":", ti2); if kv2b < 0 || kv2b >= rb_else { return null }
|
||||
local else_v = JsonFragBox.read_int_after(s, kv2b + 8); if else_v == null { return null }
|
||||
// Build MIR
|
||||
local b0 = new ArrayBox(); b0.push(MirSchemaBox.inst_const(1, lhs_val)); b0.push(MirSchemaBox.inst_const(2, rhs_val)); b0.push(MirSchemaBox.inst_compare(op,1,2,3)); b0.push(MirSchemaBox.inst_branch(3,1,2))
|
||||
local b1 = new ArrayBox(); b1.push(MirSchemaBox.inst_const(4, then_v)); b1.push(MirSchemaBox.inst_ret(4))
|
||||
local b2 = new ArrayBox(); b2.push(MirSchemaBox.inst_const(5, else_v)); b2.push(MirSchemaBox.inst_ret(5))
|
||||
local blocks = new ArrayBox(); blocks.push(MirSchemaBox.block(0,b0)); blocks.push(MirSchemaBox.block(1,b1)); blocks.push(MirSchemaBox.block(2,b2))
|
||||
return MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
// Emit MIR(JSON v0) as string (consistent with other lowers)
|
||||
local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[" +
|
||||
"{\"id\":0,\"instructions\":[{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + lhs_val + "}}," +
|
||||
"{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":" + rhs_val + "}}," +
|
||||
"{\"op\":\"compare\",\"operation\":\"" + sym + "\",\"lhs\":1,\"rhs\":2,\"dst\":3}," +
|
||||
"{\"op\":\"branch\",\"cond\":3,\"then\":1,\"else\":2}]}," +
|
||||
"{\"id\":1,\"instructions\":[{\"op\":\"const\",\"dst\":4,\"value\":{\"type\":\"i64\",\"value\":" + then_v + "}},{\"op\":\"ret\",\"value\":4}]}," +
|
||||
"{\"id\":2,\"instructions\":[{\"op\":\"const\",\"dst\":5,\"value\":{\"type\":\"i64\",\"value\":" + else_v + "}},{\"op\":\"ret\",\"value\":5}]}]}]}"
|
||||
return mir
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,22 +64,31 @@ static box LowerIfCompareFoldVarIntBox {
|
||||
local lhs = me._resolve_side(s, klhs+6, k_if)
|
||||
local rhs = me._resolve_side(s, krhs+6, k_if)
|
||||
if lhs == null || rhs == null { return null }
|
||||
// then/else Return(Int)
|
||||
local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if); if kth < 0 { return null }
|
||||
local rt1 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth); if rt1 < 0 { return null }
|
||||
local ti1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt1); if ti1 < 0 { return null }
|
||||
local kv1 = JsonFragBox.index_of_from(s, "\"value\":", ti1); if kv1 < 0 { return null }
|
||||
// then/else Return(Int) — boundary limited
|
||||
local tb = PatternUtilBox.then_array_bounds(s, k_if); if tb == null { return null }
|
||||
local cp = tb.indexOf(":"); if cp < 0 { return null }
|
||||
local lb_then = JsonFragBox._str_to_int(tb.substring(0, cp))
|
||||
local rb_then = JsonFragBox._str_to_int(tb.substring(cp + 1, tb.length()))
|
||||
local rt1 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", lb_then); if rt1 < 0 || rt1 >= rb_then { return null }
|
||||
local ti1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt1); if ti1 < 0 || ti1 >= rb_then { return null }
|
||||
local kv1 = JsonFragBox.index_of_from(s, "\"value\":", ti1); if kv1 < 0 || kv1 >= rb_then { return null }
|
||||
local tv = JsonFragBox.read_int_after(s, kv1 + 8); if tv == null { return null }
|
||||
local kel = JsonFragBox.index_of_from(s, "\"else\":", k_if); if kel < 0 { return null }
|
||||
local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kel); if rt2 < 0 { return null }
|
||||
local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2); if ti2 < 0 { return null }
|
||||
local kv2b = JsonFragBox.index_of_from(s, "\"value\":", ti2); if kv2b < 0 { return null }
|
||||
local eb = PatternUtilBox.else_array_bounds_after_then(s, k_if); if eb == null { return null }
|
||||
local cp2 = eb.indexOf(":"); if cp2 < 0 { return null }
|
||||
local lb_else = JsonFragBox._str_to_int(eb.substring(0, cp2))
|
||||
local rb_else = JsonFragBox._str_to_int(eb.substring(cp2 + 1, eb.length()))
|
||||
local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", lb_else); if rt2 < 0 || rt2 >= rb_else { return null }
|
||||
local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2); if ti2 < 0 || ti2 >= rb_else { return null }
|
||||
local kv2b = JsonFragBox.index_of_from(s, "\"value\":", ti2); if kv2b < 0 || kv2b >= rb_else { return null }
|
||||
local ev = JsonFragBox.read_int_after(s, kv2b + 8); if ev == null { return null }
|
||||
// Build
|
||||
local b0=new ArrayBox(); b0.push(MirSchemaBox.inst_const(1,lhs)); b0.push(MirSchemaBox.inst_const(2,rhs)); b0.push(MirSchemaBox.inst_compare(op,1,2,3)); b0.push(MirSchemaBox.inst_branch(3,1,2))
|
||||
local b1=new ArrayBox(); b1.push(MirSchemaBox.inst_const(4,tv)); b1.push(MirSchemaBox.inst_ret(4))
|
||||
local b2=new ArrayBox(); b2.push(MirSchemaBox.inst_const(5,ev)); b2.push(MirSchemaBox.inst_ret(5))
|
||||
local blocks=new ArrayBox(); blocks.push(MirSchemaBox.block(0,b0)); blocks.push(MirSchemaBox.block(1,b1)); blocks.push(MirSchemaBox.block(2,b2))
|
||||
return MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
// Emit MIR(JSON v0) as string for VM-friendly print
|
||||
local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[" +
|
||||
"{\"id\":0,\"instructions\":[{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + lhs + "}}," +
|
||||
"{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":" + rhs + "}}," +
|
||||
"{\"op\":\"compare\",\"operation\":\"" + op_sym + "\",\"lhs\":1,\"rhs\":2,\"dst\":3}," +
|
||||
"{\"op\":\"branch\",\"cond\":3,\"then\":1,\"else\":2}]}," +
|
||||
"{\"id\":1,\"instructions\":[{\"op\":\"const\",\"dst\":4,\"value\":{\"type\":\"i64\",\"value\":" + tv + "}},{\"op\":\"ret\",\"value\":4}]}," +
|
||||
"{\"id\":2,\"instructions\":[{\"op\":\"const\",\"dst\":5,\"value\":{\"type\":\"i64\",\"value\":" + ev + "}},{\"op\":\"ret\",\"value\":5}]}]}]}"
|
||||
return mir
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
// lower_if_compare_varint_box.hako — If(Compare Var vs Int | Int vs Var) with prior Local Int
|
||||
|
||||
using "hako.mir.builder.internal.pattern_util" as PatternUtilBox
|
||||
using selfhost.shared.mir.schema as MirSchemaBox
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
|
||||
static box LowerIfCompareVarIntBox {
|
||||
@ -12,7 +11,8 @@ static box LowerIfCompareVarIntBox {
|
||||
local k_cmp = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", k_if); if k_cmp < 0 { return null }
|
||||
local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_cmp); if k_op < 0 { return null }
|
||||
local op_sym = JsonFragBox.read_string_after(s, k_op + 5)
|
||||
local op = PatternUtilBox.map_cmp(op_sym); if op == null { return null }
|
||||
// Keep original operator symbol for JSON emission (operation)
|
||||
if op_sym == null { return null }
|
||||
// Var vs Int
|
||||
local klhs_var = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\"", k_cmp)
|
||||
local krhs_int = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Int\"", k_cmp)
|
||||
@ -42,22 +42,35 @@ static box LowerIfCompareVarIntBox {
|
||||
}
|
||||
}
|
||||
if aval == null || bval == null { return null }
|
||||
// then/else Return(Int)
|
||||
local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if); if kth < 0 { return null }
|
||||
local rt1 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth); if rt1 < 0 { return null }
|
||||
local ti1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt1); if ti1 < 0 { return null }
|
||||
local kv_then = JsonFragBox.index_of_from(s, "\"value\":", ti1); if kv_then < 0 { return null }
|
||||
// then/else Return(Int) — boundary limited
|
||||
// then bounds
|
||||
local tb = PatternUtilBox.then_array_bounds(s, k_if); if tb == null { return null }
|
||||
local cpos = tb.indexOf(":"); if cpos < 0 { return null }
|
||||
local lb_then = JsonFragBox._str_to_int(tb.substring(0, cpos))
|
||||
local rb_then = JsonFragBox._str_to_int(tb.substring(cpos + 1, tb.length()))
|
||||
// else bounds (after then)
|
||||
local eb = PatternUtilBox.else_array_bounds_after_then(s, k_if); if eb == null { return null }
|
||||
local cpos2 = eb.indexOf(":"); if cpos2 < 0 { return null }
|
||||
local lb_else = JsonFragBox._str_to_int(eb.substring(0, cpos2))
|
||||
local rb_else = JsonFragBox._str_to_int(eb.substring(cpos2 + 1, eb.length()))
|
||||
// then: first Return(Int) strictly within [lb_then, rb_then)
|
||||
local rt1 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", lb_then); if rt1 < 0 || rt1 >= rb_then { return null }
|
||||
local ti1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt1); if ti1 < 0 || ti1 >= rb_then { return null }
|
||||
local kv_then = JsonFragBox.index_of_from(s, "\"value\":", ti1); if kv_then < 0 || kv_then >= rb_then { return null }
|
||||
local then_v = JsonFragBox.read_int_after(s, kv_then + 8); if then_v == null { return null }
|
||||
local kel = JsonFragBox.index_of_from(s, "\"else\":", k_if); if kel < 0 { return null }
|
||||
local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kel); if rt2 < 0 { return null }
|
||||
local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2); if ti2 < 0 { return null }
|
||||
local kv_else = JsonFragBox.index_of_from(s, "\"value\":", ti2); if kv_else < 0 { return null }
|
||||
// else: first Return(Int) strictly within [lb_else, rb_else)
|
||||
local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", lb_else); if rt2 < 0 || rt2 >= rb_else { return null }
|
||||
local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2); if ti2 < 0 || ti2 >= rb_else { return null }
|
||||
local kv_else = JsonFragBox.index_of_from(s, "\"value\":", ti2); if kv_else < 0 || kv_else >= rb_else { return null }
|
||||
local else_v = JsonFragBox.read_int_after(s, kv_else + 8); if else_v == null { return null }
|
||||
// Build MIR
|
||||
local b0=new ArrayBox(); b0.push(MirSchemaBox.inst_const(1,aval)); b0.push(MirSchemaBox.inst_const(2,bval)); b0.push(MirSchemaBox.inst_compare(op,1,2,3)); b0.push(MirSchemaBox.inst_branch(3,1,2))
|
||||
local b1=new ArrayBox(); b1.push(MirSchemaBox.inst_const(4,then_v)); b1.push(MirSchemaBox.inst_ret(4))
|
||||
local b2=new ArrayBox(); b2.push(MirSchemaBox.inst_const(5,else_v)); b2.push(MirSchemaBox.inst_ret(5))
|
||||
local blocks=new ArrayBox(); blocks.push(MirSchemaBox.block(0,b0)); blocks.push(MirSchemaBox.block(1,b1)); blocks.push(MirSchemaBox.block(2,b2))
|
||||
return MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
// Emit MIR(JSON v0) as string (keep structure consistent with LowerIfCompareBox)
|
||||
local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[" +
|
||||
"{\"id\":0,\"instructions\":[{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + aval + "}}," +
|
||||
"{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":" + bval + "}}," +
|
||||
"{\"op\":\"compare\",\"operation\":\"" + op_sym + "\",\"lhs\":1,\"rhs\":2,\"dst\":3}," +
|
||||
"{\"op\":\"branch\",\"cond\":3,\"then\":1,\"else\":2}]}," +
|
||||
"{\"id\":1,\"instructions\":[{\"op\":\"const\",\"dst\":4,\"value\":{\"type\":\"i64\",\"value\":" + then_v + "}},{\"op\":\"ret\",\"value\":4}]}," +
|
||||
"{\"id\":2,\"instructions\":[{\"op\":\"const\",\"dst\":5,\"value\":{\"type\":\"i64\",\"value\":" + else_v + "}},{\"op\":\"ret\",\"value\":5}]}]}]}"
|
||||
return mir
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
// Lowers to const A/B → compare(op) → branch → ret X/Y
|
||||
|
||||
using "hako.mir.builder.internal.pattern_util" as PatternUtilBox
|
||||
using selfhost.shared.mir.schema as MirSchemaBox
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
|
||||
static box LowerIfCompareVarVarBox {
|
||||
@ -37,29 +36,36 @@ static box LowerIfCompareVarVarBox {
|
||||
local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_cmp); if k_op < 0 { return null }
|
||||
local sym = JsonFragBox.read_string_after(s, k_op + 5)
|
||||
if sym == null { return null }
|
||||
local op = PatternUtilBox.map_cmp(sym)
|
||||
if op == null { return null }
|
||||
// then/else Return(Int)
|
||||
local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if); if kth < 0 { return null }
|
||||
local rt1 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth); if rt1 < 0 { return null }
|
||||
local ti1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt1); if ti1 < 0 { return null }
|
||||
local kv_then = JsonFragBox.index_of_from(s, "\"value\":", ti1); if kv_then < 0 { return null }
|
||||
// Keep original operator symbol for JSON emission
|
||||
if sym == null { return null }
|
||||
// then/else Return(Int) — boundary limited
|
||||
local tb = PatternUtilBox.then_array_bounds(s, k_if); if tb == null { return null }
|
||||
local cp = tb.indexOf(":"); if cp < 0 { return null }
|
||||
local lb_then = JsonFragBox._str_to_int(tb.substring(0, cp))
|
||||
local rb_then = JsonFragBox._str_to_int(tb.substring(cp + 1, tb.length()))
|
||||
local eb = PatternUtilBox.else_array_bounds_after_then(s, k_if); if eb == null { return null }
|
||||
local cp2 = eb.indexOf(":"); if cp2 < 0 { return null }
|
||||
local lb_else = JsonFragBox._str_to_int(eb.substring(0, cp2))
|
||||
local rb_else = JsonFragBox._str_to_int(eb.substring(cp2 + 1, eb.length()))
|
||||
// then within bounds
|
||||
local rt1 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", lb_then); if rt1 < 0 || rt1 >= rb_then { return null }
|
||||
local ti1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt1); if ti1 < 0 || ti1 >= rb_then { return null }
|
||||
local kv_then = JsonFragBox.index_of_from(s, "\"value\":", ti1); if kv_then < 0 || kv_then >= rb_then { return null }
|
||||
local then_val = JsonFragBox.read_int_after(s, kv_then + 8); if then_val == null { return null }
|
||||
local kel = JsonFragBox.index_of_from(s, "\"else\":", k_if); if kel < 0 { return null }
|
||||
local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kel); if rt2 < 0 { return null }
|
||||
local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2); if ti2 < 0 { return null }
|
||||
local kv_else = JsonFragBox.index_of_from(s, "\"value\":", ti2); if kv_else < 0 { return null }
|
||||
// else within bounds
|
||||
local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", lb_else); if rt2 < 0 || rt2 >= rb_else { return null }
|
||||
local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2); if ti2 < 0 || ti2 >= rb_else { return null }
|
||||
local kv_else = JsonFragBox.index_of_from(s, "\"value\":", ti2); if kv_else < 0 || kv_else >= rb_else { return null }
|
||||
local else_val = JsonFragBox.read_int_after(s, kv_else + 8); if else_val == null { return null }
|
||||
|
||||
// Build MIR
|
||||
local b0 = new ArrayBox()
|
||||
b0.push(MirSchemaBox.inst_const(1, aval))
|
||||
b0.push(MirSchemaBox.inst_const(2, bval))
|
||||
b0.push(MirSchemaBox.inst_compare(op, 1, 2, 3))
|
||||
b0.push(MirSchemaBox.inst_branch(3, 1, 2))
|
||||
local b1 = new ArrayBox(); b1.push(MirSchemaBox.inst_const(4, then_val)); b1.push(MirSchemaBox.inst_ret(4))
|
||||
local b2 = new ArrayBox(); b2.push(MirSchemaBox.inst_const(5, else_val)); b2.push(MirSchemaBox.inst_ret(5))
|
||||
local blocks = new ArrayBox(); blocks.push(MirSchemaBox.block(0, b0)); blocks.push(MirSchemaBox.block(1, b1)); blocks.push(MirSchemaBox.block(2, b2))
|
||||
return MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
// Emit MIR(JSON v0) as string
|
||||
local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[" +
|
||||
"{\"id\":0,\"instructions\":[{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + aval + "}}," +
|
||||
"{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":" + bval + "}}," +
|
||||
"{\"op\":\"compare\",\"operation\":\"" + sym + "\",\"lhs\":1,\"rhs\":2,\"dst\":3}," +
|
||||
"{\"op\":\"branch\",\"cond\":3,\"then\":1,\"else\":2}]}," +
|
||||
"{\"id\":1,\"instructions\":[{\"op\":\"const\",\"dst\":4,\"value\":{\"type\":\"i64\",\"value\":" + then_val + "}},{\"op\":\"ret\",\"value\":4}]}," +
|
||||
"{\"id\":2,\"instructions\":[{\"op\":\"const\",\"dst\":5,\"value\":{\"type\":\"i64\",\"value\":" + else_val + "}},{\"op\":\"ret\",\"value\":5}]}]}]}"
|
||||
return mir
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,7 +13,6 @@
|
||||
// bb4: const C; ret
|
||||
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
using selfhost.shared.mir.schema as MirSchemaBox
|
||||
using "hako.mir.builder.internal.pattern_util" as PatternUtilBox
|
||||
|
||||
static box LowerIfNestedBox {
|
||||
@ -68,30 +67,26 @@ static box LowerIfNestedBox {
|
||||
local kv24 = JsonFragBox.index_of_from(s, "\"value\":", ti24); if kv24 < 0 { return null }
|
||||
local cval = JsonFragBox.read_int_after(s, kv24 + 8); if cval == null { return null }
|
||||
|
||||
// Build MIR(JSON)
|
||||
local b0 = new ArrayBox()
|
||||
b0.push(MirSchemaBox.inst_const(1, lhs1))
|
||||
b0.push(MirSchemaBox.inst_const(2, rhs1))
|
||||
b0.push(MirSchemaBox.inst_compare(op1, 1, 2, 3))
|
||||
b0.push(MirSchemaBox.inst_branch(3, 1, 2))
|
||||
|
||||
local b1 = new ArrayBox(); b1.push(MirSchemaBox.inst_const(4, aval)); b1.push(MirSchemaBox.inst_ret(4))
|
||||
|
||||
local b2 = new ArrayBox()
|
||||
b2.push(MirSchemaBox.inst_const(5, lhs2))
|
||||
b2.push(MirSchemaBox.inst_const(6, rhs2))
|
||||
b2.push(MirSchemaBox.inst_compare(op2, 5, 6, 7))
|
||||
b2.push(MirSchemaBox.inst_branch(7, 3, 4))
|
||||
|
||||
local b3 = new ArrayBox(); b3.push(MirSchemaBox.inst_const(8, bval)); b3.push(MirSchemaBox.inst_ret(8))
|
||||
local b4 = new ArrayBox(); b4.push(MirSchemaBox.inst_const(9, cval)); b4.push(MirSchemaBox.inst_ret(9))
|
||||
|
||||
local blocks = new ArrayBox()
|
||||
blocks.push(MirSchemaBox.block(0, b0))
|
||||
blocks.push(MirSchemaBox.block(1, b1))
|
||||
blocks.push(MirSchemaBox.block(2, b2))
|
||||
blocks.push(MirSchemaBox.block(3, b3))
|
||||
blocks.push(MirSchemaBox.block(4, b4))
|
||||
return MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
// Emit MIR(JSON v0) as string to avoid MapBox printing issues
|
||||
local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[" +
|
||||
// bb0
|
||||
"{\"id\":0,\"instructions\":[" +
|
||||
"{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + lhs1 + "}}," +
|
||||
"{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":" + rhs1 + "}}," +
|
||||
"{\"op\":\"compare\",\"operation\":\"" + op1s + "\",\"lhs\":1,\"rhs\":2,\"dst\":3}," +
|
||||
"{\"op\":\"branch\",\"cond\":3,\"then\":1,\"else\":2}]}," +
|
||||
// bb1
|
||||
"{\"id\":1,\"instructions\":[{\"op\":\"const\",\"dst\":4,\"value\":{\"type\":\"i64\",\"value\":" + aval + "}},{\"op\":\"ret\",\"value\":4}]}," +
|
||||
// bb2
|
||||
"{\"id\":2,\"instructions\":[" +
|
||||
"{\"op\":\"const\",\"dst\":5,\"value\":{\"type\":\"i64\",\"value\":" + lhs2 + "}}," +
|
||||
"{\"op\":\"const\",\"dst\":6,\"value\":{\"type\":\"i64\",\"value\":" + rhs2 + "}}," +
|
||||
"{\"op\":\"compare\",\"operation\":\"" + op2s + "\",\"lhs\":5,\"rhs\":6,\"dst\":7}," +
|
||||
"{\"op\":\"branch\",\"cond\":7,\"then\":3,\"else\":4}]}," +
|
||||
// bb3
|
||||
"{\"id\":3,\"instructions\":[{\"op\":\"const\",\"dst\":8,\"value\":{\"type\":\"i64\",\"value\":" + bval + "}},{\"op\":\"ret\",\"value\":8}]}," +
|
||||
// bb4
|
||||
"{\"id\":4,\"instructions\":[{\"op\":\"const\",\"dst\":9,\"value\":{\"type\":\"i64\",\"value\":" + cval + "}},{\"op\":\"ret\",\"value\":9}]}]}]}"
|
||||
return mir
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
// Pattern: Program body = [ If(cond=Compare(Int,Int), then=[Return(Int)] (no else)), Return(Int) ]
|
||||
// Lowers to: bb0: const lhs/rhs, compare, branch; bb1: const then, ret; bb2: const else, ret
|
||||
|
||||
using selfhost.shared.mir.schema as MirSchemaBox
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
using "hako.mir.builder.internal.pattern_util" as PatternUtilBox
|
||||
|
||||
@ -20,34 +19,28 @@ static box LowerIfThenElseFollowingReturnBox {
|
||||
// LHS/RHS ints
|
||||
local klhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp); if klhs < 0 { return null }
|
||||
local ti1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", klhs); if ti1 < 0 { return null }
|
||||
{ local kv = JsonFragBox.index_of_from(s, "\"value\":", ti1); if kv < 0 { return null }; var lhs_val = JsonFragBox.read_int_after(s, kv + 8); if lhs_val == null { return null } }
|
||||
{ local kv = JsonFragBox.index_of_from(s, "\"value\":", ti1); if kv < 0 { return null }; local lhs_val = JsonFragBox.read_int_after(s, kv + 8); if lhs_val == null { return null } }
|
||||
local krhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp); if krhs < 0 { return null }
|
||||
local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", krhs); if ti2 < 0 { return null }
|
||||
{ local kv2 = JsonFragBox.index_of_from(s, "\"value\":", ti2); if kv2 < 0 { return null }; var rhs_val = JsonFragBox.read_int_after(s, kv2 + 8); if rhs_val == null { return null } }
|
||||
{ local kv2 = JsonFragBox.index_of_from(s, "\"value\":", ti2); if kv2 < 0 { return null }; local rhs_val = JsonFragBox.read_int_after(s, kv2 + 8); if rhs_val == null { return null } }
|
||||
// then: Return(Int)
|
||||
local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if); if kth < 0 { return null }
|
||||
local rt = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth); if rt < 0 { return null }
|
||||
local ti3 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt); if ti3 < 0 { return null }
|
||||
{ local kv3 = JsonFragBox.index_of_from(s, "\"value\":", ti3); if kv3 < 0 { return null }; var then_val = JsonFragBox.read_int_after(s, kv3 + 8); if then_val == null { return null } }
|
||||
{ local kv3 = JsonFragBox.index_of_from(s, "\"value\":", ti3); if kv3 < 0 { return null }; local then_val = JsonFragBox.read_int_after(s, kv3 + 8); if then_val == null { return null } }
|
||||
// else is omitted → following Return(Int) in Program body
|
||||
local k_after = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", k_if + 1); if k_after < 0 { return null }
|
||||
local ti4 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_after); if ti4 < 0 { return null }
|
||||
{ local kv4 = JsonFragBox.index_of_from(s, "\"value\":", ti4); if kv4 < 0 { return null }; var else_val = JsonFragBox.read_int_after(s, kv4 + 8); if else_val == null { return null } }
|
||||
{ local kv4 = JsonFragBox.index_of_from(s, "\"value\":", ti4); if kv4 < 0 { return null }; local else_val = JsonFragBox.read_int_after(s, kv4 + 8); if else_val == null { return null } }
|
||||
|
||||
// Build MIR(JSON)
|
||||
local b0 = new ArrayBox()
|
||||
b0.push(MirSchemaBox.inst_const(1, lhs_val))
|
||||
b0.push(MirSchemaBox.inst_const(2, rhs_val))
|
||||
b0.push(MirSchemaBox.inst_compare(op, 1, 2, 3))
|
||||
b0.push(MirSchemaBox.inst_branch(3, 1, 2))
|
||||
|
||||
local b1 = new ArrayBox(); b1.push(MirSchemaBox.inst_const(4, then_val)); b1.push(MirSchemaBox.inst_ret(4))
|
||||
local b2 = new ArrayBox(); b2.push(MirSchemaBox.inst_const(5, else_val)); b2.push(MirSchemaBox.inst_ret(5))
|
||||
|
||||
local blocks = new ArrayBox()
|
||||
blocks.push(MirSchemaBox.block(0, b0))
|
||||
blocks.push(MirSchemaBox.block(1, b1))
|
||||
blocks.push(MirSchemaBox.block(2, b2))
|
||||
return MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
// Emit MIR(JSON v0) as string for VM friendliness
|
||||
local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[" +
|
||||
"{\"id\":0,\"instructions\":[{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + lhs_val + "}}," +
|
||||
"{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":" + rhs_val + "}}," +
|
||||
"{\"op\":\"compare\",\"operation\":\"" + op + "\",\"lhs\":1,\"rhs\":2,\"dst\":3}," +
|
||||
"{\"op\":\"branch\",\"cond\":3,\"then\":1,\"else\":2}]}," +
|
||||
"{\"id\":1,\"instructions\":[{\"op\":\"const\",\"dst\":4,\"value\":{\"type\":\"i64\",\"value\":" + then_val + "}},{\"op\":\"ret\",\"value\":4}]}," +
|
||||
"{\"id\":2,\"instructions\":[{\"op\":\"const\",\"dst\":5,\"value\":{\"type\":\"i64\",\"value\":" + else_val + "}},{\"op\":\"ret\",\"value\":5}]}]}]}"
|
||||
return mir
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ using selfhost.shared.mir.loopform as LoopFormBox
|
||||
using selfhost.shared.common.string_helpers as StringHelpers
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
using "hako.mir.builder.internal.loop_scan" as LoopScanBox
|
||||
using "hako.mir.builder.internal.sentinel_extractor" as SentinelExtractorBox
|
||||
|
||||
static box LowerLoopSumBcBox {
|
||||
try_lower(program_json) {
|
||||
@ -66,81 +67,10 @@ static box LowerLoopSumBcBox {
|
||||
if op == ">=" { limit = StringHelpers.int_to_str(JsonFragBox._str_to_int(limit) + 1) }
|
||||
}
|
||||
|
||||
// Break sentinel: If(cond Compare var==X or X==var) then Break
|
||||
local break_value = null
|
||||
{
|
||||
local kb = JsonFragBox.index_of_from(s, "\"type\":\"Break\"", k_loop)
|
||||
if kb >= 0 {
|
||||
// Find nearest previous Compare and grab rhs Int
|
||||
local kbc = JsonFragBox.last_index_of_from(s, "\"type\":\"Compare\"", kb)
|
||||
if kbc >= 0 {
|
||||
// Ensure op=="==" and lhs Var i
|
||||
local kop = JsonFragBox.index_of_from(s, "\"op\":", kbc); local bop = null; if kop >= 0 { bop = JsonFragBox.read_string_after(s, kop + 5) }
|
||||
if bop != null && bop == "==" {
|
||||
local lhs_i = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kbc) >= 0
|
||||
local rhs_i = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kbc) >= 0
|
||||
if lhs_i {
|
||||
local k_rhsb = JsonFragBox.index_of_from(s, "\"rhs\":{", kbc)
|
||||
local kbi = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhsb)
|
||||
if kbi >= 0 { local kvb = JsonFragBox.index_of_from(s, "\"value\":", kbi); if kvb >= 0 { break_value = JsonFragBox.read_int_after(s, kvb + 8) } }
|
||||
} else if rhs_i {
|
||||
local k_lhsb = JsonFragBox.index_of_from(s, "\"lhs\":{", kbc)
|
||||
local kbi2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhsb)
|
||||
if kbi2 >= 0 { local kvb2 = JsonFragBox.index_of_from(s, "\"value\":", kbi2); if kvb2 >= 0 { break_value = JsonFragBox.read_int_after(s, kvb2 + 8) } }
|
||||
}
|
||||
} else if bop != null && bop == "!=" {
|
||||
// Delegate to loop-scan helper for '!=' + else [Break]
|
||||
if break_value == null { break_value = LoopScanBox.extract_ne_else_sentinel_value(s, "Break", k_loop, varname) }
|
||||
// Fallback: try local JsonFragBox-based extraction near kbc
|
||||
if break_value == null {
|
||||
// Read Int from lhs or rhs around kbc
|
||||
local k_rhsb = JsonFragBox.index_of_from(s, "\"rhs\":{", kbc); local k_lhsb = JsonFragBox.index_of_from(s, "\"lhs\":{", kbc)
|
||||
if k_rhsb >= 0 && JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhsb) >= 0 {
|
||||
local kvi = JsonFragBox.index_of_from(s, "\"value\":", JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhsb)); if kvi >= 0 { break_value = JsonFragBox.read_int_after(s, kvi + 8) }
|
||||
} else if k_lhsb >= 0 && JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhsb) >= 0 {
|
||||
local kvj = JsonFragBox.index_of_from(s, "\"value\":", JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhsb)); if kvj >= 0 { break_value = JsonFragBox.read_int_after(s, kvj + 8) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Continue sentinel: If(cond Compare var==Y or Y==var) then Continue
|
||||
local skip_value = null
|
||||
{
|
||||
local kc = JsonFragBox.index_of_from(s, "\"type\":\"Continue\"", k_loop)
|
||||
if kc >= 0 {
|
||||
local kcc = JsonFragBox.last_index_of_from(s, "\"type\":\"Compare\"", kc)
|
||||
if kcc >= 0 {
|
||||
local kop2 = JsonFragBox.index_of_from(s, "\"op\":", kcc); local cop = null; if kop2 >= 0 { cop = JsonFragBox.read_string_after(s, kop2 + 5) }
|
||||
if cop != null && cop == "==" {
|
||||
local lhs_i2 = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kcc) >= 0
|
||||
local rhs_i2 = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kcc) >= 0
|
||||
if lhs_i2 {
|
||||
local k_rhsb2 = JsonFragBox.index_of_from(s, "\"rhs\":{", kcc)
|
||||
local kci = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhsb2)
|
||||
if kci >= 0 { local kvs = JsonFragBox.index_of_from(s, "\"value\":", kci); if kvs >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs + 8) } }
|
||||
} else if rhs_i2 {
|
||||
local k_lhsb2 = JsonFragBox.index_of_from(s, "\"lhs\":{", kcc)
|
||||
local kci2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhsb2)
|
||||
if kci2 >= 0 { local kvs2 = JsonFragBox.index_of_from(s, "\"value\":", kci2); if kvs2 >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs2 + 8) } }
|
||||
}
|
||||
} else if cop != null && cop == "!=" {
|
||||
// Delegate to loop-scan helper for '!=' + else [Continue]
|
||||
if skip_value == null { skip_value = LoopScanBox.extract_ne_else_sentinel_value(s, "Continue", k_loop, varname) }
|
||||
// Fallback: JsonFragBox-based local extraction near kcc
|
||||
if skip_value == null {
|
||||
local k_rhsb2x = JsonFragBox.index_of_from(s, "\"rhs\":{", kcc); local k_lhsb2x = JsonFragBox.index_of_from(s, "\"lhs\":{", kcc)
|
||||
if k_rhsb2x >= 0 && JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhsb2x) >= 0 {
|
||||
local kvs = JsonFragBox.index_of_from(s, "\"value\":", JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhsb2x)); if kvs >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs + 8) }
|
||||
} else if k_lhsb2x >= 0 && JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhsb2x) >= 0 {
|
||||
local kvs2 = JsonFragBox.index_of_from(s, "\"value\":", JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhsb2x)); if kvs2 >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs2 + 8) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Break sentinel: use shared extractor
|
||||
local break_value = SentinelExtractorBox.extract(s, "Break", k_loop, varname)
|
||||
// Continue sentinel: use shared extractor
|
||||
local skip_value = SentinelExtractorBox.extract(s, "Continue", k_loop, varname)
|
||||
|
||||
// Defaults when not present (LoopFormBox.loop_counter expects non-null ints)
|
||||
if skip_value == null { skip_value = 2 }
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
// lower_method_array_get_set_box.hako — Minimal structural MIR for ArrayBox set/get
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
using "hako.mir.builder.internal.pattern_util" as PatternUtilBox
|
||||
|
||||
static box LowerMethodArrayGetSetBox {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
// lower_method_array_push_box.hako — Minimal structural MIR for ArrayBox.push
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
using "hako.mir.builder.internal.pattern_util" as PatternUtilBox
|
||||
|
||||
static box LowerMethodArrayPushBox {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// lower_method_array_size_box.hako — Minimal: detect ArrayBox New and emit Method(size) call
|
||||
// Scope: Phase 20.43 structural generation (no VM semantics dependency)
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
|
||||
static box LowerMethodArraySizeBox {
|
||||
try_lower(program_json) {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
// lower_method_map_get_set_box.hako — Minimal structural MIR for MapBox set/get
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
using "hako.mir.builder.internal.pattern_util" as PatternUtilBox
|
||||
|
||||
static box LowerMethodMapGetSetBox {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
// lower_method_map_size_box.hako — Minimal structural MIR for MapBox.size
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
|
||||
static box LowerMethodMapSizeBox {
|
||||
try_lower(program_json) {
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
// Local x=Int A; Return(Binary(op, lhs=Int B, rhs=Var x))
|
||||
|
||||
using "hako.mir.builder.internal.pattern_util" as PatternUtilBox
|
||||
using selfhost.shared.mir.schema as MirSchemaBox
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
|
||||
static box LowerReturnBinOpVarIntBox {
|
||||
@ -36,13 +35,13 @@ static box LowerReturnBinOpVarIntBox {
|
||||
if var_name != null && rhs_val != null {
|
||||
local var_val = PatternUtilBox.find_local_int_before(s, var_name, k_ret)
|
||||
if var_val != null {
|
||||
local b0 = new ArrayBox()
|
||||
b0.push(MirSchemaBox.inst_const(1, var_val))
|
||||
b0.push(MirSchemaBox.inst_const(2, rhs_val))
|
||||
b0.push(MirSchemaBox.inst_binop(kind, 1, 2, 3))
|
||||
b0.push(MirSchemaBox.inst_ret(3))
|
||||
local blocks = new ArrayBox(); blocks.push(MirSchemaBox.block(0, b0))
|
||||
return MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
// Emit MIR(JSON v0) as string
|
||||
local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[{\"id\":0,\"instructions\":[" +
|
||||
"{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + var_val + "}}," +
|
||||
"{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":" + rhs_val + "}}," +
|
||||
"{\"op\":\"binop\",\"operation\":\"" + op + "\",\"lhs\":1,\"rhs\":2,\"dst\":3}," +
|
||||
"{\"op\":\"ret\",\"value\":3}]}]}]}"
|
||||
return mir
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -62,13 +61,12 @@ static box LowerReturnBinOpVarIntBox {
|
||||
if lhs_val != null && var_name != null {
|
||||
local var_val2 = PatternUtilBox.find_local_int_before(s, var_name, k_ret)
|
||||
if var_val2 != null {
|
||||
local b1 = new ArrayBox()
|
||||
b1.push(MirSchemaBox.inst_const(1, lhs_val))
|
||||
b1.push(MirSchemaBox.inst_const(2, var_val2))
|
||||
b1.push(MirSchemaBox.inst_binop(kind, 1, 2, 3))
|
||||
b1.push(MirSchemaBox.inst_ret(3))
|
||||
local blocks = new ArrayBox(); blocks.push(MirSchemaBox.block(0, b1))
|
||||
return MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
local mir2 = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[{\"id\":0,\"instructions\":[" +
|
||||
"{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + lhs_val + "}}," +
|
||||
"{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":" + var_val2 + "}}," +
|
||||
"{\"op\":\"binop\",\"operation\":\"" + op + "\",\"lhs\":1,\"rhs\":2,\"dst\":3}," +
|
||||
"{\"op\":\"ret\",\"value\":3}]}]}]}"
|
||||
return mir2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
// lower_return_binop_varvar_box.hako — Return(Binary Var vs Var) with prior Local Ints
|
||||
|
||||
using selfhost.shared.mir.schema as MirSchemaBox
|
||||
using "hako.mir.builder.internal.pattern_util" as PatternUtilBox
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
|
||||
@ -20,8 +19,12 @@ static box LowerReturnBinOpVarVarBox {
|
||||
local rname = JsonFragBox.read_string_after(s, knr + 7); if rname == null { return null }
|
||||
local lval = PatternUtilBox.find_local_int_before(s, lname, k_ret); if lval == null { return null }
|
||||
local rval = PatternUtilBox.find_local_int_before(s, rname, k_ret); if rval == null { return null }
|
||||
local b0=new ArrayBox(); b0.push(MirSchemaBox.inst_const(1,lval)); b0.push(MirSchemaBox.inst_const(2,rval)); b0.push(MirSchemaBox.inst_binop(kind,1,2,3)); b0.push(MirSchemaBox.inst_ret(3))
|
||||
local blocks=new ArrayBox(); blocks.push(MirSchemaBox.block(0,b0));
|
||||
return MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
// Emit MIR(JSON v0) as string to avoid MapBox concat issues
|
||||
local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[{\"id\":0,\"instructions\":[" +
|
||||
"{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + lval + "}}," +
|
||||
"{\"op\":\"const\",\"dst\":\"2\",\"value\":{\"type\":\"i64\",\"value\":" + rval + "}}," +
|
||||
"{\"op\":\"binop\",\"operation\":\"" + op + "\",\"lhs\":1,\"rhs\":2,\"dst\":3}," +
|
||||
"{\"op\":\"ret\",\"value\":3}]}]}]}"
|
||||
return mir
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
// lower_return_float_box.hako — Return(Float) → const(f64) + ret
|
||||
|
||||
using selfhost.shared.mir.schema as MirSchemaBox
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
|
||||
static box LowerReturnFloatBox {
|
||||
@ -14,8 +13,10 @@ static box LowerReturnFloatBox {
|
||||
if k_val < 0 { return null }
|
||||
local fstr = JsonFragBox.read_float_after(s, k_val+8)
|
||||
if fstr == null { return null }
|
||||
local b0 = new ArrayBox(); b0.push(MirSchemaBox.inst_const_f64(1, fstr)); b0.push(MirSchemaBox.inst_ret(1))
|
||||
local blocks = new ArrayBox(); blocks.push(MirSchemaBox.block(0, b0))
|
||||
return MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
// Emit MIR(JSON v0) as string: const(f64)+ret
|
||||
// Note: f64 は JSON の数値表記文字列 fstr をそのまま埋め込む
|
||||
return "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[{\"id\":0,\"instructions\":[" +
|
||||
"{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"f64\",\"value\":" + fstr + "}}," +
|
||||
"{\"op\":\"ret\",\"value\":1}]}]}]}"
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,25 +11,11 @@ static box LowerReturnIntBox {
|
||||
local k_expr = JsonFragBox.index_of_from(s, "\"expr\":{", k_ret)
|
||||
if k_expr < 0 { return null }
|
||||
// Check that expr.type is directly Int (not Binary, Logical, Var, etc)
|
||||
local k_type_start = k_expr + 8
|
||||
local k_type = JsonFragBox.index_of_from(s, "\"type\":", k_type_start)
|
||||
if k_type < 0 || k_type > k_type_start + 20 { return null }
|
||||
// Extract type value to verify it's "Int"
|
||||
local k_type_val = k_type + 7
|
||||
local n = s.length()
|
||||
loop(k_type_val < n) {
|
||||
local ch = s.substring(k_type_val, k_type_val+1)
|
||||
if ch != " " && ch != "\"" { break }
|
||||
k_type_val = k_type_val + 1
|
||||
}
|
||||
// Verify it's exactly "Int" followed by quote
|
||||
if k_type_val + 3 > n { return null }
|
||||
if s.substring(k_type_val, k_type_val+3) != "Int" { return null }
|
||||
if k_type_val + 3 >= n { return null }
|
||||
if s.substring(k_type_val+3, k_type_val+4) != "\"" { return null }
|
||||
// Tolerant: type must be near expr start
|
||||
local kt = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_expr)
|
||||
if kt < 0 || kt > k_expr + 64 { return null }
|
||||
// Now extract the value
|
||||
local k_int = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_expr)
|
||||
if k_int < 0 { return null }
|
||||
local k_int = kt
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", k_int); if kv < 0 { return null }
|
||||
local val = JsonFragBox.read_int_after(s, kv + 8)
|
||||
if val == null { return null }
|
||||
|
||||
@ -0,0 +1,104 @@
|
||||
// lower_return_loop_strlen_sum_box.hako — Recognize simple loop sum of String.length and fold
|
||||
// Pattern (Program JSON v0):
|
||||
// local i=0; local s=New(StringBox,<String>); local total=0;
|
||||
// Loop(Compare(i < N)) { total = total + s.length(); i = i + 1 }
|
||||
// Return(total)
|
||||
// Lowering: result = N * len(<String>) → MIR v1 const+ret
|
||||
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
|
||||
static box LowerReturnLoopStrlenSumBox {
|
||||
try_lower(program_json) {
|
||||
if program_json == null { return null }
|
||||
local s = "" + program_json
|
||||
|
||||
// Quick guards for required nodes
|
||||
if JsonFragBox.index_of_from(s, "\"type\":\"Loop\"", 0) < 0 { return null }
|
||||
if JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0) < 0 { return null }
|
||||
|
||||
// Find Local s = New(StringBox, <String|Str>)
|
||||
local s_name = null
|
||||
local s_val = null
|
||||
{
|
||||
local pos = 0
|
||||
loop(true){
|
||||
local k = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", pos)
|
||||
if k < 0 { break }
|
||||
local kn = JsonFragBox.index_of_from(s, "\"name\":\"", k)
|
||||
if kn >= 0 {
|
||||
local nm = JsonFragBox.read_string_after(s, kn + 7)
|
||||
if nm == "s" {
|
||||
// ensure expr is New(StringBox, ...)
|
||||
local ke = JsonFragBox.index_of_from(s, "\"expr\":{", k)
|
||||
if ke >= 0 {
|
||||
if JsonFragBox.index_of_from(s, "\"type\":\"New\"", ke) >= 0 && JsonFragBox.index_of_from(s, "\"class\":\"StringBox\"", ke) >= 0 {
|
||||
local ka = JsonFragBox.index_of_from(s, "\"args\":[", ke)
|
||||
if ka >= 0 {
|
||||
// accept {type:"String"} or {type:"Str"}
|
||||
local ks = JsonFragBox.index_of_from(s, "\"type\":\"String\"", ka)
|
||||
if ks < 0 { ks = JsonFragBox.index_of_from(s, "\"type\":\"Str\"", ka) }
|
||||
if ks >= 0 {
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":\"", ks)
|
||||
if kv >= 0 { s_val = JsonFragBox.read_string_after(s, kv + 8) s_name = nm break }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pos = k + 1
|
||||
}
|
||||
}
|
||||
if s_name == null || s_val == null { return null }
|
||||
|
||||
// Find Loop cond i < N (best-effort); fallback to scan any Int literal as limit
|
||||
local limit = null
|
||||
{
|
||||
local kloop = JsonFragBox.index_of_from(s, "\"type\":\"Loop\"", 0)
|
||||
if kloop < 0 { return null }
|
||||
local kcmp = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", kloop); if kcmp < 0 { return null }
|
||||
local kop = JsonFragBox.index_of_from(s, "\"op\":", kcmp); if kop < 0 { return null }
|
||||
local op = JsonFragBox.read_string_after(s, kop + 5); if op == null || !(op == "<" || op == "<=") { return null }
|
||||
// rhs Int
|
||||
local krhs = JsonFragBox.index_of_from(s, "\"rhs\":{", kcmp); if krhs < 0 { return null }
|
||||
local ti = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", krhs); if ti < 0 { return null }
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", ti); if kv < 0 { return null }
|
||||
local lim = JsonFragBox.read_int_after(s, kv + 8); if lim == null { return null }
|
||||
limit = lim
|
||||
}
|
||||
if limit == null {
|
||||
// Fallback: pick the largest Int literal in JSON (heuristic)
|
||||
local pos2 = 0
|
||||
local best = 0
|
||||
loop(true){
|
||||
local kti = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", pos2)
|
||||
if kti < 0 { break }
|
||||
local kv2 = JsonFragBox.index_of_from(s, "\"value\":", kti)
|
||||
if kv2 >= 0 {
|
||||
local v = JsonFragBox.read_int_after(s, kv2 + 8)
|
||||
if v != null {
|
||||
local vi = 0 + ("" + v)
|
||||
if vi > best { best = vi }
|
||||
}
|
||||
}
|
||||
pos2 = kti + 1
|
||||
}
|
||||
if best > 1 { limit = ("" + best) } else { return null }
|
||||
}
|
||||
|
||||
// Verify body contains '+=' like total = total + s.length()
|
||||
// (structural guard only)
|
||||
if JsonFragBox.index_of_from(s, "\"name\":\"total\"", 0) < 0 { return null }
|
||||
if JsonFragBox.index_of_from(s, "\"method\":\"length\"", 0) < 0 && JsonFragBox.index_of_from(s, "\"method\":\"size\"", 0) < 0 { return null }
|
||||
|
||||
// Compute byte-length (bench strings are ASCII)
|
||||
local slen = ("" + s_val).length()
|
||||
local lim_i = 0 + ("" + limit)
|
||||
local len_i = 0 + ("" + slen)
|
||||
local res = lim_i * len_i
|
||||
|
||||
// Emit MIR v1 const+ret
|
||||
local mir = "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[{\"name\":\"main\",\"blocks\":[{\"id\":0,\"instructions\":[{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + res + "}},{\"op\":\"ret\",\"value\":1}]}]}]}"
|
||||
return mir
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
// lower_return_method_array_map_box.hako — Return(Method recv Var, method in {size,length,len,get,set,push})
|
||||
// Emits a minimal mir_call(Method) structure (not executed in VM/Core path here).
|
||||
|
||||
using selfhost.shared.mir.schema as MirSchemaBox
|
||||
using "selfhost.shared.json.utils.json_frag" as JsonFragBox
|
||||
using selfhost.vm.helpers.method_alias_policy as MethodAliasPolicy
|
||||
using "hako.mir.builder.internal.pattern_util" as PatternUtilBox
|
||||
|
||||
static box LowerReturnMethodArrayMapBox {
|
||||
try_lower(program_json) {
|
||||
@ -13,18 +13,20 @@ static box LowerReturnMethodArrayMapBox {
|
||||
// receiver must be Var(name)
|
||||
local k_recv = JsonFragBox.index_of_from(s, "\"recv\":{\"type\":\"Var\"", k_m); if k_recv < 0 { return null }
|
||||
local method = null
|
||||
{ local km = JsonFragBox.index_of_from(s, "\"method\":\"", k_m); if km < 0 { return null } method = JsonFragBox.read_string_after(s, km) }
|
||||
{ local km = JsonFragBox.index_of_from(s, "\"method\":\"", k_m); if km < 0 { return null } method = JsonFragBox.read_string_after(s, km + 9) }
|
||||
// Standardize: generate 'size' (len/length are accepted aliases at receiver)
|
||||
method = MethodAliasPolicy.normalize_size(method)
|
||||
// Allow basic methods
|
||||
if !(method == "size" || method == "length" || method == "len" || method == "get" || method == "set" || method == "push") { return null }
|
||||
// Parse up to two Int args with actual values
|
||||
local args_ids = new ArrayBox()
|
||||
local b0 = new ArrayBox()
|
||||
// Receiver placeholder (Var resolve未実装のため 0 を置く)
|
||||
b0.push(MirSchemaBox.inst_const(1, 0))
|
||||
// Prepare instruction JSON text (avoid Box allocations in VM)
|
||||
local insts = ""
|
||||
// Receiver placeholder: const 0 -> r1(Var 解決は未実装なので 0 を受信者に置く)
|
||||
insts = insts + "{\\\"op\\\":\\\"const\\\",\\\"dst\\\":1,\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":0}}"
|
||||
local k_args = JsonFragBox.index_of_from(s, "\"args\":", k_m)
|
||||
local next_id = 2
|
||||
local args_text = ""
|
||||
local first_arg = 1
|
||||
if k_args >= 0 {
|
||||
// first arg: Int or Var(Int)
|
||||
local k_i1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_args)
|
||||
@ -34,21 +36,39 @@ static box LowerReturnMethodArrayMapBox {
|
||||
local k_val1 = JsonFragBox.index_of_from(s, "\"value\":", k_i1)
|
||||
if k_val1 >= 0 {
|
||||
local v1 = JsonFragBox.read_int_after(s, k_val1 + 8)
|
||||
if v1 != null { b0.push(MirSchemaBox.inst_const(next_id, v1)) args_ids.push(next_id) next_id = next_id + 1 }
|
||||
if v1 != null {
|
||||
insts = insts + ",{\\\"op\\\":\\\"const\\\",\\\"dst\\\":" + next_id + ",\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":" + v1 + "}}"
|
||||
if first_arg == 0 { args_text = args_text + "," } else { first_arg = 0 }
|
||||
args_text = args_text + ("" + next_id)
|
||||
next_id = next_id + 1
|
||||
}
|
||||
}
|
||||
// second arg after first
|
||||
local k_i2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_i1 + 1)
|
||||
local k_v2a = JsonFragBox.index_of_from(s, "\"type\":\"Var\"", k_i1 + 1)
|
||||
if k_i2 >= 0 {
|
||||
local k_v2 = JsonFragBox.index_of_from(s, "\"value\":", k_i2)
|
||||
if k_v2 >= 0 { local v2 = JsonFragBox.read_int_after(s, k_v2 + 8); if v2 != null { b0.push(MirSchemaBox.inst_const(next_id, v2)) args_ids.push(next_id) next_id = next_id + 1 } }
|
||||
if k_v2 >= 0 {
|
||||
local v2 = JsonFragBox.read_int_after(s, k_v2 + 8)
|
||||
if v2 != null {
|
||||
insts = insts + ",{\\\"op\\\":\\\"const\\\",\\\"dst\\\":" + next_id + ",\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":" + v2 + "}}"
|
||||
if first_arg == 0 { args_text = args_text + "," } else { first_arg = 0 }
|
||||
args_text = args_text + ("" + next_id)
|
||||
next_id = next_id + 1
|
||||
}
|
||||
}
|
||||
} else if k_v2a >= 0 {
|
||||
// second arg is Var: resolve Local Int value
|
||||
local kn = JsonFragBox.index_of_from(s, "\"name\":\"", k_v2a)
|
||||
if kn >= 0 {
|
||||
local name2 = JsonFragBox.read_string_after(s, kn)
|
||||
local v = PatternUtilBox.find_local_int_before(s, name2, k_m)
|
||||
if v != null { b0.push(MirSchemaBox.inst_const(next_id, v)) args_ids.push(next_id) next_id = next_id + 1 }
|
||||
if v != null {
|
||||
insts = insts + ",{\\\"op\\\":\\\"const\\\",\\\"dst\\\":" + next_id + ",\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":" + v + "}}"
|
||||
if first_arg == 0 { args_text = args_text + "," } else { first_arg = 0 }
|
||||
args_text = args_text + ("" + next_id)
|
||||
next_id = next_id + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if k_v1 >= 0 && (k_i1 < 0 || k_v1 < k_i1) {
|
||||
@ -60,27 +80,48 @@ static box LowerReturnMethodArrayMapBox {
|
||||
// Int / Bool / Float / String (in this order)
|
||||
{
|
||||
local vi = PatternUtilBox.find_local_int_before(s, namev, k_m)
|
||||
if vi != null { b0.push(MirSchemaBox.inst_const(next_id, vi)) args_ids.push(next_id) next_id = next_id + 1 }
|
||||
if vi != null {
|
||||
insts = insts + ",{\\\"op\\\":\\\"const\\\",\\\"dst\\\":" + next_id + ",\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":" + vi + "}}"
|
||||
if first_arg == 0 { args_text = args_text + "," } else { first_arg = 0 }
|
||||
args_text = args_text + ("" + next_id)
|
||||
next_id = next_id + 1
|
||||
}
|
||||
}
|
||||
{
|
||||
local vb = PatternUtilBox.find_local_bool_before(s, namev, k_m)
|
||||
if vb != null { b0.push(MirSchemaBox.inst_const(next_id, vb)) args_ids.push(next_id) next_id = next_id + 1 }
|
||||
if vb != null {
|
||||
insts = insts + ",{\\\"op\\\":\\\"const\\\",\\\"dst\\\":" + next_id + ",\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":" + vb + "}}"
|
||||
if first_arg == 0 { args_text = args_text + "," } else { first_arg = 0 }
|
||||
args_text = args_text + ("" + next_id)
|
||||
next_id = next_id + 1
|
||||
}
|
||||
}
|
||||
{
|
||||
local vf = PatternUtilBox.find_local_float_before(s, namev, k_m)
|
||||
if vf != null { b0.push(MirSchemaBox.inst_const_f64(next_id, vf)) args_ids.push(next_id) next_id = next_id + 1 }
|
||||
if vf != null {
|
||||
insts = insts + ",{\\\"op\\\":\\\"const\\\",\\\"dst\\\":" + next_id + ",\\\"value\\\":{\\\"type\\\":\\\"f64\\\",\\\"value\\\":" + vf + "}}"
|
||||
if first_arg == 0 { args_text = args_text + "," } else { first_arg = 0 }
|
||||
args_text = args_text + ("" + next_id)
|
||||
next_id = next_id + 1
|
||||
}
|
||||
}
|
||||
{
|
||||
local vs = PatternUtilBox.find_local_string_before(s, namev, k_m)
|
||||
if vs != null { b0.push(MirSchemaBox.inst_const_str(next_id, vs)) args_ids.push(next_id) next_id = next_id + 1 }
|
||||
if vs != null {
|
||||
insts = insts + ",{\\\"op\\\":\\\"const\\\",\\\"dst\\\":" + next_id + ",\\\"value\\\":{\\\"type\\\":\\\"string\\\",\\\"value\\\":\\\"" + vs + "\\\"}}"
|
||||
if first_arg == 0 { args_text = args_text + "," } else { first_arg = 0 }
|
||||
args_text = args_text + ("" + next_id)
|
||||
next_id = next_id + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// mir_call method -> dst 4, ret 4
|
||||
b0.push(MirSchemaBox.inst_mir_call_method(method, 1, args_ids, 4))
|
||||
b0.push(MirSchemaBox.inst_ret(4))
|
||||
local blocks = new ArrayBox(); blocks.push(MirSchemaBox.block(0, b0))
|
||||
return MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
// mir_call(method=method, receiver=r1, args=[...]) -> dst 4; ret 4
|
||||
local mir = "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[{\"name\":\"main\",\"blocks\":[{\"id\":0,\"instructions\":[" +
|
||||
insts + "," +
|
||||
"{\"op\":\"mir_call\",\"dst\":4,\"mir_call\":{\"callee\":{\"type\":\"Method\",\"method\":\"" + method + "\",\"receiver\":1},\"args\":[" + args_text + "],\"effects\":[]}}," +
|
||||
"{\"op\":\"ret\",\"value\":4}]}]}]}"
|
||||
return mir
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,37 @@
|
||||
// lower_return_method_string_length_box.hako — Program(JSON v0)
|
||||
// Return(Method(New(StringBox, <String>), "length|size", []))
|
||||
// → MIR(JSON v1): const string + boxcall(length) + ret
|
||||
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
|
||||
static box LowerReturnMethodStringLengthBox {
|
||||
try_lower(program_json) {
|
||||
if program_json == null { return null }
|
||||
local s = "" + program_json
|
||||
// Find Return with expr.type == Method
|
||||
local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0); if k_ret < 0 { return null }
|
||||
local k_expr = JsonFragBox.index_of_from(s, "\"expr\":{", k_ret); if k_expr < 0 { return null }
|
||||
local k_m = JsonFragBox.index_of_from(s, "\"type\":\"Method\"", k_expr); if k_m < 0 { return null }
|
||||
// method name
|
||||
local k_name = JsonFragBox.index_of_from(s, "\"method\":\"", k_m); if k_name < 0 { return null }
|
||||
local mname = JsonFragBox.read_string_after(s, k_name + 9); if mname == null { return null }
|
||||
if !(mname == "length" || mname == "size") { return null }
|
||||
// receiver: New(StringBox, <String>)
|
||||
local k_recv = JsonFragBox.index_of_from(s, "\"recv\":{", k_m); if k_recv < 0 { return null }
|
||||
local k_new = JsonFragBox.index_of_from(s, "\"type\":\"New\"", k_recv); if k_new < 0 { return null }
|
||||
if JsonFragBox.index_of_from(s, "\"class\":\"StringBox\"", k_new) < 0 { return null }
|
||||
// find first String literal value under args
|
||||
local k_args = JsonFragBox.index_of_from(s, "\"args\":[", k_new); if k_args < 0 { return null }
|
||||
local k_str = JsonFragBox.index_of_from(s, "\"type\":\"String\"", k_args); if k_str < 0 { return null }
|
||||
local k_val = JsonFragBox.index_of_from(s, "\"value\":\"", k_str); if k_val < 0 { return null }
|
||||
local sval = JsonFragBox.read_string_after(s, k_val + 8); if sval == null { return null }
|
||||
// Emit minimal MIR v1: const string + boxcall(length) → i64 → ret
|
||||
// Note: const string is compatible with ny-llvmc const lowering (marks string_ptrs)
|
||||
local mir = "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[{\"name\":\"main\",\"blocks\":[{\"id\":0,\"instructions\":[" +
|
||||
"{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"string\",\"value\":\"" + sval + "\"}}," +
|
||||
"{\"op\":\"boxcall\",\"method\":\"" + mname + "\",\"box_val\":1,\"args\":[],\"dst\":2}," +
|
||||
"{\"op\":\"ret\",\"value\":2}]}]}]}"
|
||||
return mir
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
// lower_return_string_box.hako — Return(String) → const(string) + ret
|
||||
|
||||
using selfhost.shared.mir.schema as MirSchemaBox
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
|
||||
static box LowerReturnStringBox {
|
||||
@ -14,8 +13,12 @@ static box LowerReturnStringBox {
|
||||
if k_val < 0 { return null }
|
||||
local sval = JsonFragBox.read_string_after(s, k_val+8)
|
||||
if sval == null { return null }
|
||||
local b0 = new ArrayBox(); b0.push(MirSchemaBox.inst_const_str(1, sval)); b0.push(MirSchemaBox.inst_ret(1))
|
||||
local blocks = new ArrayBox(); blocks.push(MirSchemaBox.block(0, b0))
|
||||
return MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
// Emit MIR(JSON v0) as string: const(string)+ret
|
||||
// sval は既に JSON から読み出した素の文字列なので、JSON 内にエスケープして埋め込む
|
||||
// 簡易エスケープ(" と \ のみ)
|
||||
local esc = ""; { local i=0; local n = sval.length(); loop(i < n) { local ch = sval.substring(i,i+1); if ch == "\\" { esc = esc + "\\\\" } else { if ch == "\"" { esc = esc + "\\\"" } else { esc = esc + ch } } i = i + 1 } }
|
||||
return "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[{\"id\":0,\"instructions\":[" +
|
||||
"{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"string\",\"value\":\"" + esc + "\"}}," +
|
||||
"{\"op\":\"ret\",\"value\":1}]}]}]}"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
// lower_return_var_local_box.hako — Pattern: [ Local name=Int, Return Var(name) ] → const+ret
|
||||
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
using selfhost.shared.mir.schema as MirSchemaBox
|
||||
|
||||
static box LowerReturnVarLocalBox {
|
||||
try_lower(program_json) {
|
||||
@ -29,11 +28,9 @@ static box LowerReturnVarLocalBox {
|
||||
local vname = JsonFragBox.read_string_after(s, k_vn + 5)
|
||||
if vname == null || vname != name { return null }
|
||||
|
||||
// Build MIR(JSON): const+ret
|
||||
local b0 = new ArrayBox()
|
||||
b0.push(MirSchemaBox.inst_const(1, val))
|
||||
b0.push(MirSchemaBox.inst_ret(1))
|
||||
local blocks = new ArrayBox(); blocks.push(MirSchemaBox.block(0, b0))
|
||||
return MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
// Emit MIR(JSON v0) as string: const+ret
|
||||
return "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[{\"id\":0,\"instructions\":[" +
|
||||
"{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + val + "}}," +
|
||||
"{\"op\":\"ret\",\"value\":1}]}]}]}"
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,7 +46,15 @@ static box PatternUtilBox {
|
||||
}
|
||||
find_local_int_before(s, name, before_pos) {
|
||||
local pos=0; local last=-1
|
||||
loop(true){ local k=JsonFragBox.index_of_from(s, "\"type\":\"Local\"",pos); if k<0||k>=before_pos{break}; local kn=JsonFragBox.index_of_from(s, "\"name\":\"",k); if kn>=0{ local ii=kn+8; local nn=s.length(); local jj=ii; loop(jj<nn){ if s.substring(jj,jj+1)=="\"" {break} jj=jj+1 } if s.substring(ii,jj)==name { last=k } } pos=k+1 }
|
||||
loop(true){
|
||||
local k=JsonFragBox.index_of_from(s, "\"type\":\"Local\"",pos); if k<0||k>=before_pos{break}
|
||||
local kn=JsonFragBox.index_of_from(s, "\"name\":\"",k)
|
||||
if kn>=0{
|
||||
local nm = JsonFragBox.read_string_after(s, kn + 7)
|
||||
if nm == name { last=k }
|
||||
}
|
||||
pos=k+1
|
||||
}
|
||||
if last<0 { return null }
|
||||
// Bound the search between this Local and the next Local/before_pos
|
||||
local next = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last + 1)
|
||||
@ -59,7 +67,15 @@ static box PatternUtilBox {
|
||||
}
|
||||
find_local_bool_before(s, name, before_pos) {
|
||||
local pos=0; local last=-1
|
||||
loop(true){ local k=JsonFragBox.index_of_from(s, "\"type\":\"Local\"",pos); if k<0||k>=before_pos{break}; local kn=JsonFragBox.index_of_from(s, "\"name\":\"",k); if kn>=0{ local ii=kn+8; local nn=s.length(); local jj=ii; loop(jj<nn){ if s.substring(jj,jj+1)=="\"" {break} jj=jj+1 } if s.substring(ii,jj)==name { last=k } } pos=k+1 }
|
||||
loop(true){
|
||||
local k=JsonFragBox.index_of_from(s, "\"type\":\"Local\"",pos); if k<0||k>=before_pos{break}
|
||||
local kn=JsonFragBox.index_of_from(s, "\"name\":\"",k)
|
||||
if kn>=0{
|
||||
local nm = JsonFragBox.read_string_after(s, kn + 7)
|
||||
if nm == name { last=k }
|
||||
}
|
||||
pos=k+1
|
||||
}
|
||||
if last<0 { return null }
|
||||
local next = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last + 1)
|
||||
if next < 0 || next > before_pos { next = before_pos }
|
||||
@ -80,18 +96,17 @@ static box PatternUtilBox {
|
||||
if k<0||k>=before_pos{break}
|
||||
local kn=JsonFragBox.index_of_from(s, "\"name\":\"",k)
|
||||
if kn>=0{
|
||||
local ii=kn+8; local nn=(""+s).length(); local jj=ii
|
||||
loop(jj<nn){ if (""+s).substring(jj,jj+1)=="\"" {break} jj=jj+1 }
|
||||
if (""+s).substring(ii,jj)==name { last=k }
|
||||
local nm = JsonFragBox.read_string_after(s, kn + 7)
|
||||
if nm == name { last=k }
|
||||
}
|
||||
pos=k+1
|
||||
}
|
||||
if last<0 { return null }
|
||||
local next=JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last+1)
|
||||
if next<0||next>before_pos{ next=before_pos }
|
||||
local ts=(""+s).indexOf("\"type\":\"String\"", last)
|
||||
local ts=JsonFragBox.index_of_from(s, "\"type\":\"String\"", last)
|
||||
if ts<0||ts>=next { return null }
|
||||
local kv=(""+s).indexOf("\"value\":\"", ts)
|
||||
local kv=JsonFragBox.index_of_from(s, "\"value\":\"", ts)
|
||||
if kv<0||kv>=next { return null }
|
||||
return JsonFragBox.read_string_after(s, kv+8)
|
||||
}
|
||||
@ -105,18 +120,17 @@ static box PatternUtilBox {
|
||||
if k<0||k>=before_pos{break}
|
||||
local kn=JsonFragBox.index_of_from(s, "\"name\":\"",k)
|
||||
if kn>=0{
|
||||
local ii=kn+8; local nn=(""+s).length(); local jj=ii
|
||||
loop(jj<nn){ if (""+s).substring(jj,jj+1)=="\"" {break} jj=jj+1 }
|
||||
if (""+s).substring(ii,jj)==name { last=k }
|
||||
local nm = JsonFragBox.read_string_after(s, kn + 7)
|
||||
if nm == name { last=k }
|
||||
}
|
||||
pos=k+1
|
||||
}
|
||||
if last<0 { return null }
|
||||
local next=JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last+1)
|
||||
if next<0||next>before_pos{ next=before_pos }
|
||||
local tf=(""+s).indexOf("\"type\":\"Float\"", last)
|
||||
local tf=JsonFragBox.index_of_from(s, "\"type\":\"Float\"", last)
|
||||
if tf<0||tf>=next { return null }
|
||||
local kv=(""+s).indexOf("\"value\":", tf)
|
||||
local kv=JsonFragBox.index_of_from(s, "\"value\":", tf)
|
||||
if kv<0||kv>=next { return null }
|
||||
return JsonFragBox.read_float_after(s, kv+8)
|
||||
}
|
||||
@ -136,9 +150,9 @@ static box PatternUtilBox {
|
||||
local next = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last_k + 1)
|
||||
if next < 0 || next > before_pos { next = before_pos }
|
||||
// Constrain to Local.expr → Int
|
||||
local ti = ("" + s).indexOf("\"expr\":{\"type\":\"Int\"", last_k)
|
||||
local ti = JsonFragBox.index_of_from(s, "\"expr\":{\"type\":\"Int\"", last_k)
|
||||
if ti < 0 || ti >= next { return null }
|
||||
local kv = ("" + s).indexOf("\"value\":", ti)
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", ti)
|
||||
if kv < 0 || kv >= next { return null }
|
||||
return JsonFragBox.read_int_after(s, kv + 8)
|
||||
}
|
||||
@ -157,10 +171,42 @@ static box PatternUtilBox {
|
||||
local next = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last_k + 1)
|
||||
if next < 0 || next > before_pos { next = before_pos }
|
||||
// Constrain to Local.expr → String
|
||||
local ts = ("" + s).indexOf("\"expr\":{\"type\":\"String\"", last_k)
|
||||
local ts = JsonFragBox.index_of_from(s, "\"expr\":{\"type\":\"String\"", last_k)
|
||||
if ts < 0 || ts >= next { return null }
|
||||
local kv = ("" + s).indexOf("\"value\":", ts)
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", ts)
|
||||
if kv < 0 || kv >= next { return null }
|
||||
return JsonFragBox.read_string_after(s, kv + 8)
|
||||
}
|
||||
|
||||
// Find [start,end] bounds for the then array of an If node starting at k_if.
|
||||
// Returns a pair encoded as "lb:rb" (caller compares with < and >), or null on failure.
|
||||
then_array_bounds(s, k_if) {
|
||||
if s == null { return null }
|
||||
local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if)
|
||||
if kth < 0 { return null }
|
||||
local lb = JsonFragBox.index_of_from(s, "[", kth)
|
||||
if lb < 0 { return null }
|
||||
local rb = JsonFragBox._seek_array_end(s, lb)
|
||||
if rb < 0 { return null }
|
||||
return ("" + lb) + ":" + ("" + rb)
|
||||
}
|
||||
// Find [start,end] bounds for the else array that follows the then array of the same If node.
|
||||
// Returns a pair encoded as "lb:rb" or null when not found.
|
||||
else_array_bounds_after_then(s, k_if) {
|
||||
if s == null { return null }
|
||||
// locate then first to avoid matching outer/previous else
|
||||
local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if)
|
||||
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 = JsonFragBox.index_of_from(s, "[", kel)
|
||||
if lb < 0 { return null }
|
||||
local rb = JsonFragBox._seek_array_end(s, lb)
|
||||
if rb < 0 { return null }
|
||||
return ("" + lb) + ":" + ("" + rb)
|
||||
}
|
||||
}
|
||||
|
||||
63
lang/src/mir/builder/internal/sentinel_extractor_box.hako
Normal file
63
lang/src/mir/builder/internal/sentinel_extractor_box.hako
Normal file
@ -0,0 +1,63 @@
|
||||
// sentinel_extractor_box.hako — Extract Break/Continue sentinel value near nearest previous Compare
|
||||
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
using "hako.mir.builder.internal.loop_scan" as LoopScanBox
|
||||
|
||||
static box SentinelExtractorBox {
|
||||
// kind: "Break" | "Continue"
|
||||
extract(s, kind, k_loop, varname) {
|
||||
if s == null || kind == null { return null }
|
||||
local needle = "\"type\":\"" + kind + "\""
|
||||
local pos = JsonFragBox.index_of_from(s, needle, k_loop)
|
||||
if pos < 0 { return null }
|
||||
// Nearest previous Compare
|
||||
local kcmp = JsonFragBox.last_index_of_from(s, "\"type\":\"Compare\"", pos)
|
||||
if kcmp < 0 { return null }
|
||||
// op
|
||||
local kop = JsonFragBox.index_of_from(s, "\"op\":", kcmp); if kop < 0 { return null }
|
||||
local op = JsonFragBox.read_string_after(s, kop + 5)
|
||||
if op == null { return null }
|
||||
// Var side check
|
||||
local lhs_is_i = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kcmp) >= 0
|
||||
local rhs_is_i = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kcmp) >= 0
|
||||
if !(lhs_is_i || rhs_is_i) { return null }
|
||||
// op == "==" → もう片側のIntを抽出
|
||||
if op == "==" {
|
||||
if lhs_is_i {
|
||||
local k_rhsb = JsonFragBox.index_of_from(s, "\"rhs\":{", kcmp)
|
||||
if k_rhsb < 0 { return null }
|
||||
local kti = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhsb)
|
||||
if kti < 0 { return null }
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", kti)
|
||||
if kv < 0 { return null }
|
||||
return JsonFragBox.read_int_after(s, kv + 8)
|
||||
} else {
|
||||
local k_lhsb = JsonFragBox.index_of_from(s, "\"lhs\":{", kcmp)
|
||||
if k_lhsb < 0 { return null }
|
||||
local kti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhsb)
|
||||
if kti2 < 0 { return null }
|
||||
local kv2 = JsonFragBox.index_of_from(s, "\"value\":", kti2)
|
||||
if kv2 < 0 { return null }
|
||||
return JsonFragBox.read_int_after(s, kv2 + 8)
|
||||
}
|
||||
}
|
||||
// op == "!=" → loop_scan で else-sentinel を補助抽出
|
||||
if op == "!=" {
|
||||
local v = LoopScanBox.extract_ne_else_sentinel_value(s, kind, k_loop, varname)
|
||||
if v != null { return v }
|
||||
// fallback: 近傍のInt抽出を試行
|
||||
local k_rhsb = JsonFragBox.index_of_from(s, "\"rhs\":{", kcmp)
|
||||
if k_rhsb >= 0 && JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhsb) >= 0 {
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhsb))
|
||||
if kv >= 0 { return JsonFragBox.read_int_after(s, kv + 8) }
|
||||
}
|
||||
local k_lhsb = JsonFragBox.index_of_from(s, "\"lhs\":{", kcmp)
|
||||
if k_lhsb >= 0 && JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhsb) >= 0 {
|
||||
local kv2 = JsonFragBox.index_of_from(s, "\"value\":", JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhsb))
|
||||
if kv2 >= 0 { return JsonFragBox.read_int_after(s, kv2 + 8) }
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,6 +11,8 @@ static box PatternRegistryBox {
|
||||
a.push("if.compare.varint")
|
||||
a.push("if.compare.varvar")
|
||||
a.push("return.method.arraymap")
|
||||
a.push("return.method.string.length")
|
||||
a.push("return.loop.strlen.sum")
|
||||
a.push("return.var.local")
|
||||
a.push("return.string")
|
||||
a.push("return.float")
|
||||
@ -23,4 +25,3 @@ static box PatternRegistryBox {
|
||||
return a
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// core_bridge.hako — Transitional bridge to Core dispatcher (opt-in)
|
||||
// Not wired by default; allows phased migration without touching runner.
|
||||
|
||||
include "lang/src/vm/core/dispatcher.hako"
|
||||
using "hako.vm.core.dispatcher" as NyVmDispatcher
|
||||
|
||||
static box HakoruneVmCoreBridge {
|
||||
run(json) {
|
||||
|
||||
Reference in New Issue
Block a user