diff --git a/CHANGELOG.md b/CHANGELOG.md index 39f0b23e..5291f682 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,14 @@ This changelog tracks high‑level milestones while Core MIR and Phase 12 evolve. For detailed per‑file history, see git log and docs under `docs/development/roadmap/`. ## 2025‑09‑06 + +### Phase 22.3 (Kernel Minimal C Runtime — design wrap) +- Added minimal C runtime crate (design-stage): `crates/nyash_kernel_min_c` (staticlib). +- LLVM extern lowering: normalized `nyash.console.*` → `nyash_console_*` for C linkage. +- Hako-first MIR emit stabilized via wrapper (`tools/hakorune_emit_mir.sh`): Stage‑B JSON is emitted with `NYASH_JSON_ONLY=1` and sanitized; builder falls back to Rust CLI on failure (defaults keep quick green). + +### Prep for Phase 21.10 (LLVM line — crate backend) +- Backend selector and S3 canaries exist; print EXE canary currently SKIP pending small normalization. Next: enable print EXE PASS with env‑guarded normalization in ny‑llvmc (no default behavior changes). - Core‑13 flip complete: code/tests enforce Core‑13 minimal kernel. Normalizations (Array/Ref→BoxCall, TypeCheck/Cast/Barrier/WeakRef unification) are ON by default via env (NYASH_MIR_CORE13=1). New tests validate normalization. - Docs synced: step‑50 marked done; DEV quickstart points to Core‑13 reference. diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index 69095557..59ae4142 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -1,4 +1,26 @@ -# Current Task — Phase 21.4(Hako Parser → Analyzer / Self‑Host) +# Current Task — Phase 21.10(LLVM line – crate backend print EXE) + +Status (22.3 wrap) +- 22.3 締め: 最小Cランタイム(設計)/Cシンボル整合(nyash.console.*→nyash_console_*)を反映。 +- Hako-first MIR emit は wrapper 経由で安定(Stage‑B 出力の RC 混入を抑止、Hako→失敗時は Rust CLI にフォールバック)。 +- 緑条件は quick 代表セット + phase2231 canary(rc=42)で確認済み。 + +Next (this phase) — 22.x continuation +1) TLV配線(既定OFF)+ parityカナリア + - 既存の `nyash-tlv`(optional / feature `tlv-shim`)を `src/runtime/plugin_ffi_common.rs` に薄く配線。 + - 制御: feature + `HAKO_TLV_SHIM=1`(トレース `HAKO_TLV_SHIM_TRACE{,_DETAIL}`)。 + - 受け入れ: ON/OFF で実行/rc 同一(parity)+ トレース観測が可能。 + +2) SSOTメッセージ・相対推定の整形 + 代表カナリアの常時化 + - 曖昧時のメッセージ統一(件数+先頭N、legacy委譲の明記)。 + - cwd vs using_paths 優先の明文化・軽量canaryを quick 常時化。 + +3) ビルダーの JsonFragBox / PatternUtilBox 採用(差分小さい箇所から) + - 手書きスキャンの置換を段階導入。If/Compare VarInt / Return BinOp VarVar 周辺を優先。 + +4) C‑core 一点通し(Map.set)+ parity維持(既定OFF) + - feature+ENV で no‑op 経路を通し、ON/OFF parity をカナリアで検証。 + 目的(このフェーズで到達するゴール) - Hako Parser(MVP)で AST JSON v0 を出力し、Analyzer の一次入力に採用(text は fallback 維持)。 @@ -41,6 +63,10 @@ Toggles quicklist - EXE‑first: `SMOKES_ENABLE_SELFHOST=1`(既定OFF) - TLV: `--features tlv-shim` + `HAKO_TLV_SHIM=1`(既定OFF/配線は無害な identity) - Using SSOT: `HAKO_USING_SSOT=1`(MVP は現行解決ロジックを経由しつつタグ出力) +- ENV consolidation(既定不変) + - NY compiler: 主 `NYASH_USE_NY_COMPILER`、alias `NYASH_DISABLE_NY_COMPILER`/`HAKO_DISABLE_NY_COMPILER`(受理+警告、一度だけ) + - LLVM opt: 主 `NYASH_LLVM_OPT_LEVEL`、alias `HAKO_LLVM_OPT_LEVEL`(受理+警告、一度だけ) + - Gate‑C: 主 `NYASH_GATE_C_CORE`、alias `HAKO_GATE_C_CORE`(受理+警告、一度だけ) 22.1 progress (today) - TLV配線(最小導線・既定OFF) diff --git a/README.md b/README.md index bdc156dc..c24a09cb 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,18 @@ **A Seriously-Crafted Hobby Language** **From Zero to Native Binary in 20 Days - The AI-Powered Language Revolution** +Quick — Emit MIR (Hako‑first helper) +- Generate MIR(JSON) from a Hako file using the Stage‑B parser + MirBuilder (wrapper falls back to the Rust CLI builder on failure to keep runs green): + +``` +tools/hakorune_emit_mir.sh path/to/program.hako /tmp/program.mir.json +target/release/hakorune --mir-json-file /tmp/program.mir.json +``` + +Notes +- The wrapper runs Stage‑B with `NYASH_JSON_ONLY=1` to keep the output clean (no `RC:` lines). +- When the Hako MirBuilder fails (e.g., under development), it automatically falls back to `--program-json-to-mir` (no behavior change by default). + *[🇯🇵 日本語版はこちら / Japanese Version](README.ja.md)* [![Selfhost Minimal](https://github.com/moe-charm/nyash/actions/workflows/selfhost-minimal.yml/badge.svg?branch=selfhosting-dev)](https://github.com/moe-charm/nyash/actions/workflows/selfhost-minimal.yml) diff --git a/crates/nyash-llvm-compiler/src/main.rs b/crates/nyash-llvm-compiler/src/main.rs index 550291ac..ae0c9649 100644 --- a/crates/nyash-llvm-compiler/src/main.rs +++ b/crates/nyash-llvm-compiler/src/main.rs @@ -6,6 +6,7 @@ use std::process::Command; use anyhow::{bail, Context, Result}; use clap::{ArgAction, Parser}; +use serde_json::Value as JsonValue; #[derive(Parser, Debug)] #[command( @@ -86,29 +87,59 @@ fn main() -> Result<()> { return Ok(()); } - // Prepare input JSON path: either from file or stdin -> temp file + // Prepare input JSON path: either from file or stdin -> temp file. + // Optionally normalize canary JSON into the shape expected by the Python builder + // when HAKO_LLVM_CANARY_NORMALIZE=1 (no default behavior change). let mut temp_path: Option = None; + let canary_norm = env::var("HAKO_LLVM_CANARY_NORMALIZE").ok().as_deref() == Some("1"); let input_path = if args.infile == "-" { let mut buf = String::new(); std::io::stdin() .read_to_string(&mut buf) .context("reading MIR JSON from stdin")?; - // Basic sanity check that it's JSON - let _: serde_json::Value = + let mut val: serde_json::Value = serde_json::from_str(&buf).context("stdin does not contain valid JSON")?; + if canary_norm { + val = normalize_canary_json(val); + } let tmp = std::env::temp_dir().join("ny_llvmc_stdin.json"); let mut f = File::create(&tmp).context("create temp json file")?; - f.write_all(buf.as_bytes()).context("write temp json")?; + let out = serde_json::to_vec(&val).context("serialize normalized json")?; + f.write_all(&out).context("write temp json")?; temp_path = Some(tmp.clone()); tmp } else { - PathBuf::from(&args.infile) + let p = PathBuf::from(&args.infile); + if canary_norm { + // Read file, normalize, and write to a temp path + let mut buf = String::new(); + File::open(&p).and_then(|mut f| f.read_to_string(&mut buf)).context("read input json")?; + let mut val: serde_json::Value = serde_json::from_str(&buf).context("input is not valid JSON")?; + val = normalize_canary_json(val); + let tmp = std::env::temp_dir().join("ny_llvmc_in.json"); + let mut f = File::create(&tmp).context("create temp json file")?; + let out = serde_json::to_vec(&val).context("serialize normalized json")?; + f.write_all(&out).context("write temp json")?; + temp_path = Some(tmp.clone()); + tmp + } else { + p + } }; if !input_path.exists() { bail!("input JSON not found: {}", input_path.display()); } + // Optional: preflight shape/hints (best-effort; no behavior change) + if let Ok(s) = std::fs::read_to_string(&input_path) { + if let Ok(val) = serde_json::from_str::(&s) { + if let Some(hint) = shape_hint(&val) { + eprintln!("[ny-llvmc/hint] {}", hint); + } + } + } + // Produce object first let obj_path = if emit_exe { let mut p = args.out.clone(); @@ -118,6 +149,20 @@ fn main() -> Result<()> { args.out.clone() }; + // Optional: print concise shape hint in verbose mode when not normalizing + if env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") && env::var("HAKO_LLVM_CANARY_NORMALIZE").ok().as_deref() != Some("1") { + if let Ok(mut f) = File::open(&input_path) { + let mut buf = String::new(); + if f.read_to_string(&mut buf).is_ok() { + if let Ok(val) = serde_json::from_str::(&buf) { + if let Some(h) = shape_hint(&val) { + eprintln!("[ny-llvmc/hint] {}", h); + } + } + } + } + } + run_harness_in(&harness_path, &input_path, &obj_path).with_context(|| { format!( "failed to compile MIR JSON via harness: {}", @@ -144,6 +189,93 @@ fn main() -> Result<()> { Ok(()) } +/// Return a concise hint if the MIR JSON likely has a schema/shape mismatch for the Python harness. +fn shape_hint(v: &JsonValue) -> Option { + // Accept both v0/v1 tolerant; only emit hint on common canary shapes + // 1) schema_version numeric 1 rather than string "1.0" + if let Some(sv) = v.get("schema_version") { + if sv.is_number() { + if sv.as_i64() == Some(1) { + return Some("schema_version=1 detected; set to \"1.0\" or enable HAKO_LLVM_CANARY_NORMALIZE=1".into()); + } + } else if sv.as_str() == Some("1") { + return Some("schema_version=\"1\" detected; prefer \"1.0\" or enable HAKO_LLVM_CANARY_NORMALIZE=1".into()); + } + } + // 2) blocks use 'inst' instead of 'instructions' + if let Some(funcs) = v.get("functions") { + if let Some(arr) = funcs.as_array() { + for f in arr { + if let Some(blocks) = f.get("blocks").and_then(|b| b.as_array()) { + for b in blocks { + if b.get("inst").is_some() && b.get("instructions").is_none() { + return Some("block key 'inst' found; rename to 'instructions' or enable HAKO_LLVM_CANARY_NORMALIZE=1".into()); + } + } + } + } + } + } + None +} + +/// Normalize a very small canary JSON into the shape expected by the Python harness. +/// - Accepts schema_version as number or string; coerces to "1.0" when 1. +/// - Renames block key 'inst' -> 'instructions'. +/// - Converts const {"ty":"i64","value":N} into {"value":{"type":"i64","value":N}} +fn normalize_canary_json(mut v: serde_json::Value) -> serde_json::Value { + use serde_json::{Map, Value}; + // schema_version: number 1 -> string "1.0" + match v.get_mut("schema_version") { + Some(Value::Number(n)) if n.as_i64() == Some(1) => { + *v.get_mut("schema_version").unwrap() = Value::String("1.0".to_string()); + } + Some(Value::String(s)) if s == "1" => { + *v.get_mut("schema_version").unwrap() = Value::String("1.0".to_string()); + } + _ => {} + } + // functions as array + if let Some(funcs) = v.get_mut("functions") { + if let Value::Array(ref mut arr) = funcs { + for func in arr.iter_mut() { + if let Value::Object(ref mut fm) = func { + if let Some(blocks_v) = fm.get_mut("blocks") { + if let Value::Array(ref mut blks) = blocks_v { + for blk in blks.iter_mut() { + if let Value::Object(ref mut bm) = blk { + // Rename 'inst' -> 'instructions' + if let Some(insts) = bm.remove("inst") { + bm.insert("instructions".to_string(), insts); + } + // Normalize instructions + if let Some(Value::Array(ref mut ins_arr)) = bm.get_mut("instructions") { + for ins in ins_arr.iter_mut() { + if let Value::Object(ref mut im) = ins { + if im.get("op").and_then(|x| x.as_str()) == Some("const") { + // if 'ty' and flat 'value' exist, wrap into typed value + if let (Some(ty), Some(val)) = (im.remove("ty"), im.remove("value")) { + let mut val_obj = Map::new(); + if let Value::String(ts) = ty { val_obj.insert("type".to_string(), Value::String(ts)); } + else { val_obj.insert("type".to_string(), ty); } + val_obj.insert("value".to_string(), val); + im.insert("value".to_string(), Value::Object(val_obj)); + } + } + } + } + } + } + } + } + } + } + } + } + } + v +} + fn run_harness_dummy(harness: &Path, out: &Path) -> Result<()> { ensure_python()?; let mut cmd = Command::new("python3"); @@ -182,10 +314,13 @@ fn ensure_python() -> Result<()> { } fn propagate_opt_level(cmd: &mut Command) { - let level = env::var("HAKO_LLVM_OPT_LEVEL") - .ok() - .or_else(|| env::var("NYASH_LLVM_OPT_LEVEL").ok()); + let hako = env::var("HAKO_LLVM_OPT_LEVEL").ok(); + let nyash = env::var("NYASH_LLVM_OPT_LEVEL").ok(); + let level = nyash.clone().or(hako.clone()); if let Some(level) = level { + if hako.is_some() && nyash.is_none() { + eprintln!("[deprecate/env] 'HAKO_LLVM_OPT_LEVEL' is deprecated; use 'NYASH_LLVM_OPT_LEVEL'"); + } cmd.env("HAKO_LLVM_OPT_LEVEL", &level); cmd.env("NYASH_LLVM_OPT_LEVEL", &level); } diff --git a/crates/nyash_kernel_min_c/src/kernel_min.c b/crates/nyash_kernel_min_c/src/kernel_min.c index 298f1c09..2d344659 100644 --- a/crates/nyash_kernel_min_c/src/kernel_min.c +++ b/crates/nyash_kernel_min_c/src/kernel_min.c @@ -17,8 +17,6 @@ long nyash_box_from_i8_string(char* p) { return 0; } -// Optional minimal stubs (not used by default; reserved for future reps) -long nyash_array_birth_h(void) { return 1; } -long nyash_array_length_h(long handle) { (void)handle; return 0; } -long nyash_map_birth_h(void) { return 1; } -long nyash_map_size_h(long handle) { (void)handle; return 0; } +// Note: Additional array/map stubs intentionally omitted to avoid symbol +// clashes with the full NyKernel when linked together. Keep this file minimal +// (console only) for print canaries. diff --git a/docs/ENV_VARS.md b/docs/ENV_VARS.md index 147e9668..c6682996 100644 --- a/docs/ENV_VARS.md +++ b/docs/ENV_VARS.md @@ -2,6 +2,10 @@ This document lists the environment flags introduced or used by the Phase 22.1 work. Defaults are OFF and behavior remains unchanged unless noted. +- NYASH_JSON_ONLY=0|1 + - Quiet JSON pipelines: suppresses `RC:` and routine logs on stdout (diagnostics still go to stderr). + - Used by Stage‑B → Program(JSON) emit to keep the output clean for downstream processing. + - HAKO_USING_SSOT=0|1 - Enables the SSOT resolver gate in the runner pipeline. - When ON, resolution first consults the SSOT bridge (modules-only MVP). If not resolved, it falls back to the existing resolver. @@ -91,13 +95,34 @@ LLVM backend selector (builder wrapper) - `crate`: uses `./target/release/ny-llvmc` (build with `cargo build -p nyash-llvm-compiler --release`). - `native`: reserved for future Hako-native builder. - Linking extras for `--emit exe`: pass via `HAKO_AOT_LDFLAGS` (e.g., `-static`), `ny-llvmc` consumes `--libs`. + - Note: crate 経路では ny_main の戻り値(i64)がプロセスの終了コードに反映されます(rc mapping)。 + +- HAKO_LLVM_CANARY_NORMALIZE=0|1 + - 開発/カナリア専用の正規化スイッチ。`1` のとき、最小の JSON 形状差(`schema_version=1` → `"1.0"`、`blocks.inst` → `instructions`、`const` の `ty/value` 包装)を自動補正してからビルドします。 + - 既定は `0`(無効)。既存ツールの挙動は変わりません。`NYASH_CLI_VERBOSE=1` のとき形状ヒントを `[ny-llvmc/hint]` で出力します。 Name mapping note (EXE link convenience) - nyash.console.* は C リンク時にシンボル名 `nyash_console_*` に正規化される(ドット→アンダースコア)。 - 例: `externcall nyash.console.log(i8*)` → C シンボル `nyash_console_log`。 - 最小 C ランタイム(Phase 22.3)の `nyash-kernel-min-c` は `nyash_console_log(char*)` を提供(設計段階)。 - + Kernel Minimal C Runtime (Phase 22.3 — design) - NYASH_KERNEL_C_MIN=0|1 - Reserved toggle for enabling the minimal C runtime shims(design‑stage; defaults OFF) - Build: `cargo build --release -p nyash-kernel-min-c`(not linked by default) + +ENV consolidation (aliases) +- NY compiler path + - Primary: `NYASH_USE_NY_COMPILER=0|1` + - Accepted aliases (deprecated; prints a one‑time warning): + - `NYASH_DISABLE_NY_COMPILER=1` → equivalent to `NYASH_USE_NY_COMPILER=0` + - `HAKO_DISABLE_NY_COMPILER=1` → equivalent to `NYASH_USE_NY_COMPILER=0` +- LLVM opt level + - Primary: `NYASH_LLVM_OPT_LEVEL` + - Accepted alias (deprecated; one‑time warning): `HAKO_LLVM_OPT_LEVEL` +- Gate‑C (Core direct route) + - Primary: `NYASH_GATE_C_CORE` + - Accepted alias (deprecated; one‑time warning): `HAKO_GATE_C_CORE` + +Notes +- Primary keys are preferred and will be kept. Aliases remain accepted for a grace period and emit a concise deprecation line once per process. diff --git a/lang/src/mir/builder/internal/lower_if_compare_box.hako b/lang/src/mir/builder/internal/lower_if_compare_box.hako index c9f1425d..cf5d032d 100644 --- a/lang/src/mir/builder/internal/lower_if_compare_box.hako +++ b/lang/src/mir/builder/internal/lower_if_compare_box.hako @@ -5,51 +5,51 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox static box LowerIfCompareBox { try_lower(program_json) { local s = "" + program_json - local k_if = s.indexOf("\"type\":\"If\"") + local k_if = JsonFragBox.index_of_from(s, "\"type\":\"If\"", 0) if k_if < 0 { return null } // cond Compare - 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 { return null } - local k_op = s.indexOf("\"op\":", k_cmp) + local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_cmp) if k_op < 0 { return null } local op = JsonFragBox.read_string_after(s, k_op + 5) if op == null { return null } if !(op == "<" || op == ">" || op == "<=" || op == ">=" || op == "==" || op == "!=") { return null } // lhs/rhs ints - local klhs = s.indexOf("\"lhs\":{", k_cmp) + local klhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp) if klhs < 0 { return null } - local ti = s.indexOf("\"type\":\"Int\"", klhs) + local ti = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", klhs) if ti < 0 { return null } - local kv_lhs = s.indexOf("\"value\":", ti) + local kv_lhs = JsonFragBox.index_of_from(s, "\"value\":", ti) if kv_lhs < 0 { return null } local lhs_val = JsonFragBox.read_int_after(s, kv_lhs + 8) if lhs_val == null { return null } - local krhs = s.indexOf("\"rhs\":{", k_cmp) + local krhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp) if krhs < 0 { return null } - local ti2 = s.indexOf("\"type\":\"Int\"", krhs) + local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", krhs) if ti2 < 0 { return null } - local kv_rhs = s.indexOf("\"value\":", ti2) + local kv_rhs = JsonFragBox.index_of_from(s, "\"value\":", ti2) 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 = s.indexOf("\"then\":", k_if) + local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if) if kth < 0 { return null } - local rt = s.indexOf("\"type\":\"Return\"", kth) + local rt = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth) if rt < 0 { return null } - local ti3 = s.indexOf("\"type\":\"Int\"", rt) + local ti3 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt) if ti3 < 0 { return null } - local kv_then = s.indexOf("\"value\":", ti3) + 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 = s.indexOf("\"else\":", k_if) + local kel = JsonFragBox.index_of_from(s, "\"else\":", k_if) if kel < 0 { return null } - local rt2 = s.indexOf("\"type\":\"Return\"", kel) + local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kel) if rt2 < 0 { return null } - local ti4 = s.indexOf("\"type\":\"Int\"", rt2) + local ti4 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2) if ti4 < 0 { return null } - local kv_else = s.indexOf("\"value\":", ti4) + 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 } diff --git a/lang/src/mir/builder/internal/lower_if_compare_fold_binints_box.hako b/lang/src/mir/builder/internal/lower_if_compare_fold_binints_box.hako index cd8321bf..d9dbc81d 100644 --- a/lang/src/mir/builder/internal/lower_if_compare_fold_binints_box.hako +++ b/lang/src/mir/builder/internal/lower_if_compare_fold_binints_box.hako @@ -7,15 +7,15 @@ 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 = s.indexOf("\"op\":\"", k_bin_start); if kop < 0 { return null } + 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) if !(op == "+" || op == "-" || op == "*" || op == "/") { return null } - local kli = s.indexOf("\"type\":\"Int\"", k_bin_start); if kli < 0 { return null } - local kvl = s.indexOf("\"value\":", kli); if kvl < 0 { 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 } local l = JsonFragBox.read_int_after(s, kvl + 8); if l == null { return null } // rhs int - local kri = s.indexOf("\"type\":\"Int\"", kli + 1); if kri < 0 { return null } - local kv2 = s.indexOf("\"value\":", kri); if kv2 < 0 { return null } + local kri = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", kli + 1); if kri < 0 { return null } + local kv2 = JsonFragBox.index_of_from(s, "\"value\":", kri); if kv2 < 0 { return null } local r = JsonFragBox.read_int_after(s, kv2 + 8); if r == null { return null } // compute local li = 0; local ri = 0; // string to int by simple parse (assume i64 fits) @@ -32,17 +32,17 @@ static box LowerIfCompareFoldBinIntsBox { // node may be Int, Binary(Int,Int), or Var with Local Int before if_pos if node_pos < 0 { return null } // Int - if s.indexOf("\"type\":\"Int\"", node_pos) == node_pos { // best-effort - local kv = s.indexOf("\"value\":", node_pos); if kv < 0 { return null } + if JsonFragBox.index_of_from(s, "\"type\":\"Int\"", node_pos) == node_pos { // best-effort + local kv = JsonFragBox.index_of_from(s, "\"value\":", node_pos); if kv < 0 { return null } return JsonFragBox.read_int_after(s, kv + 8) } // Binary - if s.indexOf("\"type\":\"Binary\"", node_pos) == node_pos { + if JsonFragBox.index_of_from(s, "\"type\":\"Binary\"", node_pos) == node_pos { return me._fold_bin_ints(s, node_pos) } // Var(name) - if s.indexOf("\"type\":\"Var\"", node_pos) == node_pos { - local kn = s.indexOf("\"name\":\"", node_pos); if kn < 0 { return null } + if JsonFragBox.index_of_from(s, "\"type\":\"Var\"", node_pos) == node_pos { + local kn = JsonFragBox.index_of_from(s, "\"name\":\"", node_pos); if kn < 0 { return null } local name = JsonFragBox.read_string_after(s, kn + 5); if name == null { return null } // find last matching Local Int before if_pos via util return PatternUtilBox.find_local_int_before(s, name, if_pos) @@ -51,29 +51,29 @@ static box LowerIfCompareFoldBinIntsBox { } try_lower(program_json){ local s = "" + program_json - local k_if = s.indexOf("\"type\":\"If\""); if k_if < 0 { return null } - local k_cmp = s.indexOf("\"type\":\"Compare\"", k_if); if k_cmp < 0 { return null } - local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null } + local k_if = JsonFragBox.index_of_from(s, "\"type\":\"If\"", 0); if k_if < 0 { return null } + 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 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 } // locate lhs/rhs node starts (Var/Int/Binary) - local klhs = s.indexOf("\"lhs\":{", k_cmp); if klhs < 0 { return null } - local krhs = s.indexOf("\"rhs\":{", k_cmp); if krhs < 0 { return null } + local klhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp); if klhs < 0 { return null } + local krhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp); if krhs < 0 { return null } local lhs_pos = klhs + 6 local rhs_pos = krhs + 6 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 = s.indexOf("\"then\":", k_if); if kth < 0 { return null } - local rt1 = s.indexOf("\"type\":\"Return\"", kth); if rt1 < 0 { return null } - local ti1 = s.indexOf("\"type\":\"Int\"", rt1); if ti1 < 0 { return null } - local kv1 = s.indexOf("\"value\":", ti1); if kv1 < 0 { return null } + 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 } local then_v = JsonFragBox.read_int_after(s, kv1 + 8); if then_v == null { return null } - local kel = s.indexOf("\"else\":", k_if); if kel < 0 { return null } - local rt2 = s.indexOf("\"type\":\"Return\"", kel); if rt2 < 0 { return null } - local ti2 = s.indexOf("\"type\":\"Int\"", rt2); if ti2 < 0 { return null } - local kv2b = s.indexOf("\"value\":", ti2); if kv2b < 0 { 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 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)) diff --git a/lang/src/mir/builder/internal/lower_if_compare_fold_varint_box.hako b/lang/src/mir/builder/internal/lower_if_compare_fold_varint_box.hako index fd15222c..041365f0 100644 --- a/lang/src/mir/builder/internal/lower_if_compare_fold_varint_box.hako +++ b/lang/src/mir/builder/internal/lower_if_compare_fold_varint_box.hako @@ -7,24 +7,24 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox static box LowerIfCompareFoldVarIntBox { _fold_bin_varint(s, k_bin, if_pos) { // Binary with one Var and one Int; resolve Var via Local and compute result - local kop = s.indexOf("\"op\":\"", k_bin); if kop < 0 { return null } + local kop = JsonFragBox.index_of_from(s, "\"op\":\"", k_bin); if kop < 0 { return null } local op = JsonFragBox.read_string_after(s, kop + 5) if !(op=="+"||op=="-"||op=="*"||op=="/") { return null } - local klv = s.indexOf("\"lhs\":{\"type\":\"Var\"", k_bin) - local kli = s.indexOf("\"lhs\":{\"type\":\"Int\"", k_bin) - local krv = s.indexOf("\"rhs\":{\"type\":\"Var\"", k_bin) - local kri = s.indexOf("\"rhs\":{\"type\":\"Int\"", k_bin) + local klv = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\"", k_bin) + local kli = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Int\"", k_bin) + local krv = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\"", k_bin) + local kri = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Int\"", k_bin) local vval = null; local ival = null if klv >= 0 && kri >= 0 { - local kn = s.indexOf("\"name\":", klv); if kn < 0 { return null } + local kn = JsonFragBox.index_of_from(s, "\"name\":", klv); if kn < 0 { return null } local name = JsonFragBox.read_string_after(s, kn + 7) vval = PatternUtilBox.find_local_int_before(s, name, if_pos) - local kv = s.indexOf("\"value\":", kri); if kv < 0 { return null } + local kv = JsonFragBox.index_of_from(s, "\"value\":", kri); if kv < 0 { return null } ival = JsonFragBox.read_int_after(s, kv + 8) } else if kli >= 0 && krv >= 0 { - local kv2 = s.indexOf("\"value\":", kli); if kv2 < 0 { return null } + local kv2 = JsonFragBox.index_of_from(s, "\"value\":", kli); if kv2 < 0 { return null } ival = JsonFragBox.read_int_after(s, kv2 + 8) - local kn2 = s.indexOf("\"name\":", krv); if kn2 < 0 { return null } + local kn2 = JsonFragBox.index_of_from(s, "\"name\":", krv); if kn2 < 0 { return null } local name2 = JsonFragBox.read_string_after(s, kn2 + 7) vval = PatternUtilBox.find_local_int_before(s, name2, if_pos) } @@ -36,17 +36,17 @@ static box LowerIfCompareFoldVarIntBox { } _resolve_side(s, node_pos, if_pos) { // Try Int - if s.indexOf("\"type\":\"Int\"", node_pos) == node_pos { - local kv = s.indexOf("\"value\":", node_pos); if kv < 0 { return null } + if JsonFragBox.index_of_from(s, "\"type\":\"Int\"", node_pos) == node_pos { + local kv = JsonFragBox.index_of_from(s, "\"value\":", node_pos); if kv < 0 { return null } return JsonFragBox.read_int_after(s, kv + 8) } // Binary(Var,Int) or (Int,Var) - if s.indexOf("\"type\":\"Binary\"", node_pos) == node_pos { + if JsonFragBox.index_of_from(s, "\"type\":\"Binary\"", node_pos) == node_pos { return me._fold_bin_varint(s, node_pos, if_pos) } // Var → Local Int - if s.indexOf("\"type\":\"Var\"", node_pos) == node_pos { - local kn = s.indexOf("\"name\":", node_pos); if kn < 0 { return null } + if JsonFragBox.index_of_from(s, "\"type\":\"Var\"", node_pos) == node_pos { + local kn = JsonFragBox.index_of_from(s, "\"name\":", node_pos); if kn < 0 { return null } local name = JsonFragBox.read_string_after(s, kn + 7) return PatternUtilBox.find_local_int_before(s, name, if_pos) } @@ -54,26 +54,26 @@ static box LowerIfCompareFoldVarIntBox { } try_lower(program_json){ local s = "" + program_json - local k_if = s.indexOf("\"type\":\"If\""); if k_if < 0 { return null } - local k_cmp = s.indexOf("\"type\":\"Compare\"", k_if); if k_cmp < 0 { return null } - local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null } + local k_if = JsonFragBox.index_of_from(s, "\"type\":\"If\"", 0); if k_if < 0 { return null } + 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 } - local klhs = s.indexOf("\"lhs\":{", k_cmp); if klhs < 0 { return null } - local krhs = s.indexOf("\"rhs\":{", k_cmp); if krhs < 0 { return null } + local klhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp); if klhs < 0 { return null } + local krhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp); if krhs < 0 { return null } 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 = s.indexOf("\"then\":", k_if); if kth < 0 { return null } - local rt1 = s.indexOf("\"type\":\"Return\"", kth); if rt1 < 0 { return null } - local ti1 = s.indexOf("\"type\":\"Int\"", rt1); if ti1 < 0 { return null } - local kv1 = s.indexOf("\"value\":", ti1); if kv1 < 0 { return null } + 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 } local tv = JsonFragBox.read_int_after(s, kv1 + 8); if tv == null { return null } - local kel = s.indexOf("\"else\":", k_if); if kel < 0 { return null } - local rt2 = s.indexOf("\"type\":\"Return\"", kel); if rt2 < 0 { return null } - local ti2 = s.indexOf("\"type\":\"Int\"", rt2); if ti2 < 0 { return null } - local kv2b = s.indexOf("\"value\":", ti2); if kv2b < 0 { 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 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)) diff --git a/lang/src/mir/builder/internal/lower_if_compare_varint_box.hako b/lang/src/mir/builder/internal/lower_if_compare_varint_box.hako index 15ad820a..7f357047 100644 --- a/lang/src/mir/builder/internal/lower_if_compare_varint_box.hako +++ b/lang/src/mir/builder/internal/lower_if_compare_varint_box.hako @@ -7,50 +7,51 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox static box LowerIfCompareVarIntBox { try_lower(program_json){ local s = "" + program_json - local k_if = s.indexOf("\"type\":\"If\""); if k_if < 0 { return null } - local k_cmp = s.indexOf("\"type\":\"Compare\"", k_if); if k_cmp < 0 { return null } - local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null } + // Locate If → Compare → op using robust index_of_from helpers + local k_if = JsonFragBox.index_of_from(s, "\"type\":\"If\"", 0); if k_if < 0 { return null } + 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 } // Var vs Int - local klhs_var = s.indexOf("\"lhs\":{\"type\":\"Var\"", k_cmp) - local krhs_int = s.indexOf("\"rhs\":{\"type\":\"Int\"", k_cmp) + 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) local aval=null; local bval=null if klhs_var >= 0 && krhs_int >= 0 { - local k_name = s.indexOf("\"name\":", klhs_var); if k_name < 0 { return null } + local k_name = JsonFragBox.index_of_from(s, "\"name\":", klhs_var); if k_name < 0 { return null } local name = JsonFragBox.read_string_after(s, k_name + 7) aval = PatternUtilBox.find_local_int_before(s, name, k_if) - local ki = s.indexOf("\"type\":\"Int\"", krhs_int) + local ki = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", krhs_int) if ki >= 0 { - local kv = s.indexOf("\"value\":", ki); if kv < 0 { return null } + local kv = JsonFragBox.index_of_from(s, "\"value\":", ki); if kv < 0 { return null } bval = JsonFragBox.read_int_after(s, kv + 8) } } else { // Int vs Var - local klhs_int = s.indexOf("\"lhs\":{\"type\":\"Int\"", k_cmp) - local krhs_var = s.indexOf("\"rhs\":{\"type\":\"Var\"", k_cmp) + local klhs_int = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Int\"", k_cmp) + local krhs_var = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\"", k_cmp) if klhs_int >= 0 && krhs_var >= 0 { - local ki2 = s.indexOf("\"type\":\"Int\"", klhs_int) + local ki2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", klhs_int) if ki2 >= 0 { - local kv2 = s.indexOf("\"value\":", ki2); if kv2 < 0 { return null } + local kv2 = JsonFragBox.index_of_from(s, "\"value\":", ki2); if kv2 < 0 { return null } aval = JsonFragBox.read_int_after(s, kv2 + 8) } - local k_name2 = s.indexOf("\"name\":", krhs_var); if k_name2 < 0 { return null } + local k_name2 = JsonFragBox.index_of_from(s, "\"name\":", krhs_var); if k_name2 < 0 { return null } local name2 = JsonFragBox.read_string_after(s, k_name2 + 7) if name2 != null { bval = PatternUtilBox.find_local_int_before(s, name2, k_if) } } } if aval == null || bval == null { return null } // then/else Return(Int) - local kth = s.indexOf("\"then\":", k_if); if kth < 0 { return null } - local rt1 = s.indexOf("\"type\":\"Return\"", kth); if rt1 < 0 { return null } - local ti1 = s.indexOf("\"type\":\"Int\"", rt1); if ti1 < 0 { return null } - local kv_then = s.indexOf("\"value\":", ti1); if kv_then < 0 { return null } + 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 } local then_v = JsonFragBox.read_int_after(s, kv_then + 8); if then_v == null { return null } - local kel = s.indexOf("\"else\":", k_if); if kel < 0 { return null } - local rt2 = s.indexOf("\"type\":\"Return\"", kel); if rt2 < 0 { return null } - local ti2 = s.indexOf("\"type\":\"Int\"", rt2); if ti2 < 0 { return null } - local kv_else = s.indexOf("\"value\":", ti2); if kv_else < 0 { 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 } 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)) diff --git a/lang/src/mir/builder/internal/lower_if_compare_varvar_box.hako b/lang/src/mir/builder/internal/lower_if_compare_varvar_box.hako index c4c2c3d6..e8d17344 100644 --- a/lang/src/mir/builder/internal/lower_if_compare_varvar_box.hako +++ b/lang/src/mir/builder/internal/lower_if_compare_varvar_box.hako @@ -11,21 +11,21 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox static box LowerIfCompareVarVarBox { try_lower(program_json) { local s = "" + program_json - local k_if = s.indexOf("\"type\":\"If\"") + local k_if = JsonFragBox.index_of_from(s, "\"type\":\"If\"", 0) if k_if < 0 { return null } - 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 { return null } // LHS/RHS Var names local lhs_name = null - local klhs = s.indexOf("\"lhs\":{\"type\":\"Var\"", k_cmp) + local klhs = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\"", k_cmp) if klhs >= 0 { - local k_name_lhs = s.indexOf("\"name\":", klhs); if k_name_lhs < 0 { return null } + local k_name_lhs = JsonFragBox.index_of_from(s, "\"name\":", klhs); if k_name_lhs < 0 { return null } lhs_name = JsonFragBox.read_string_after(s, k_name_lhs + 7) } local rhs_name = null - local krhs = s.indexOf("\"rhs\":{\"type\":\"Var\"", k_cmp) + local krhs = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\"", k_cmp) if krhs >= 0 { - local k_name_rhs = s.indexOf("\"name\":", krhs); if k_name_rhs < 0 { return null } + local k_name_rhs = JsonFragBox.index_of_from(s, "\"name\":", krhs); if k_name_rhs < 0 { return null } rhs_name = JsonFragBox.read_string_after(s, k_name_rhs + 7) } if lhs_name == null || rhs_name == null { return null } @@ -34,21 +34,21 @@ static box LowerIfCompareVarVarBox { local bval = PatternUtilBox.find_local_int_before(s, rhs_name, k_if) if aval == null || bval == null { return null } // op map - local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null } + 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 = s.indexOf("\"then\":", k_if); if kth < 0 { return null } - local rt1 = s.indexOf("\"type\":\"Return\"", kth); if rt1 < 0 { return null } - local ti1 = s.indexOf("\"type\":\"Int\"", rt1); if ti1 < 0 { return null } - local kv_then = s.indexOf("\"value\":", ti1); if kv_then < 0 { return null } + 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 } local then_val = JsonFragBox.read_int_after(s, kv_then + 8); if then_val == null { return null } - local kel = s.indexOf("\"else\":", k_if); if kel < 0 { return null } - local rt2 = s.indexOf("\"type\":\"Return\"", kel); if rt2 < 0 { return null } - local ti2 = s.indexOf("\"type\":\"Int\"", rt2); if ti2 < 0 { return null } - local kv_else = s.indexOf("\"value\":", ti2); if kv_else < 0 { 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 } local else_val = JsonFragBox.read_int_after(s, kv_else + 8); if else_val == null { return null } // Build MIR diff --git a/lang/src/mir/builder/internal/lower_if_nested_box.hako b/lang/src/mir/builder/internal/lower_if_nested_box.hako index ad1c16c3..eced39ed 100644 --- a/lang/src/mir/builder/internal/lower_if_nested_box.hako +++ b/lang/src/mir/builder/internal/lower_if_nested_box.hako @@ -19,53 +19,53 @@ using "hako.mir.builder.internal.pattern_util" as PatternUtilBox static box LowerIfNestedBox { try_lower(program_json) { local s = "" + program_json - local k_if1 = s.indexOf("\"type\":\"If\"") + local k_if1 = JsonFragBox.index_of_from(s, "\"type\":\"If\"", 0) if k_if1 < 0 { return null } - local k_cmp1 = s.indexOf("\"type\":\"Compare\"", k_if1) + local k_cmp1 = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", k_if1) if k_cmp1 < 0 { return null } - local kop1 = s.indexOf("\"op\":", k_cmp1); if kop1 < 0 { return null } + local kop1 = JsonFragBox.index_of_from(s, "\"op\":", k_cmp1); if kop1 < 0 { return null } local op1s = JsonFragBox.read_string_after(s, kop1 + 5); if op1s == null { return null } local op1 = PatternUtilBox.map_cmp(op1s); if op1 == null { return null } - local klhs1 = s.indexOf("\"lhs\":{", k_cmp1); if klhs1 < 0 { return null } - local ti11 = s.indexOf("\"type\":\"Int\"", klhs1); if ti11 < 0 { return null } - local kv11 = s.indexOf("\"value\":", ti11); if kv11 < 0 { return null } + local klhs1 = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp1); if klhs1 < 0 { return null } + local ti11 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", klhs1); if ti11 < 0 { return null } + local kv11 = JsonFragBox.index_of_from(s, "\"value\":", ti11); if kv11 < 0 { return null } local lhs1 = JsonFragBox.read_int_after(s, kv11 + 8); if lhs1 == null { return null } - local krhs1 = s.indexOf("\"rhs\":{", k_cmp1); if krhs1 < 0 { return null } - local ti12 = s.indexOf("\"type\":\"Int\"", krhs1); if ti12 < 0 { return null } - local kv12 = s.indexOf("\"value\":", ti12); if kv12 < 0 { return null } + local krhs1 = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp1); if krhs1 < 0 { return null } + local ti12 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", krhs1); if ti12 < 0 { return null } + local kv12 = JsonFragBox.index_of_from(s, "\"value\":", ti12); if kv12 < 0 { return null } local rhs1 = JsonFragBox.read_int_after(s, kv12 + 8); if rhs1 == null { return null } // then Return(Int A) - local kth = s.indexOf("\"then\":", k_if1); if kth < 0 { return null } - local rt1 = s.indexOf("\"type\":\"Return\"", kth); if rt1 < 0 { return null } - local ti13 = s.indexOf("\"type\":\"Int\"", rt1); if ti13 < 0 { return null } - local kv13 = s.indexOf("\"value\":", ti13); if kv13 < 0 { return null } + local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if1); if kth < 0 { return null } + local rt1 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth); if rt1 < 0 { return null } + local ti13 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt1); if ti13 < 0 { return null } + local kv13 = JsonFragBox.index_of_from(s, "\"value\":", ti13); if kv13 < 0 { return null } local aval = JsonFragBox.read_int_after(s, kv13 + 8); if aval == null { return null } // else contains nested If with Return(Int)/Return(Int) - local kel = s.indexOf("\"else\":", k_if1); if kel < 0 { return null } - local k_if2 = s.indexOf("\"type\":\"If\"", kel); if k_if2 < 0 { return null } - local k_cmp2 = s.indexOf("\"type\":\"Compare\"", k_if2); if k_cmp2 < 0 { return null } - local kop2 = s.indexOf("\"op\":", k_cmp2); if kop2 < 0 { return null } + local kel = JsonFragBox.index_of_from(s, "\"else\":", k_if1); if kel < 0 { return null } + local k_if2 = JsonFragBox.index_of_from(s, "\"type\":\"If\"", kel); if k_if2 < 0 { return null } + local k_cmp2 = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", k_if2); if k_cmp2 < 0 { return null } + local kop2 = JsonFragBox.index_of_from(s, "\"op\":", k_cmp2); if kop2 < 0 { return null } local op2s = JsonFragBox.read_string_after(s, kop2 + 5); if op2s == null { return null } local op2 = PatternUtilBox.map_cmp(op2s); if op2 == null { return null } - local klhs2 = s.indexOf("\"lhs\":{", k_cmp2); if klhs2 < 0 { return null } - local ti21 = s.indexOf("\"type\":\"Int\"", klhs2); if ti21 < 0 { return null } - local kv21 = s.indexOf("\"value\":", ti21); if kv21 < 0 { return null } + local klhs2 = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp2); if klhs2 < 0 { return null } + local ti21 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", klhs2); if ti21 < 0 { return null } + local kv21 = JsonFragBox.index_of_from(s, "\"value\":", ti21); if kv21 < 0 { return null } local lhs2 = JsonFragBox.read_int_after(s, kv21 + 8); if lhs2 == null { return null } - local krhs2 = s.indexOf("\"rhs\":{", k_cmp2); if krhs2 < 0 { return null } - local ti22 = s.indexOf("\"type\":\"Int\"", krhs2); if ti22 < 0 { return null } - local kv22 = s.indexOf("\"value\":", ti22); if kv22 < 0 { return null } + local krhs2 = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp2); if krhs2 < 0 { return null } + local ti22 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", krhs2); if ti22 < 0 { return null } + local kv22 = JsonFragBox.index_of_from(s, "\"value\":", ti22); if kv22 < 0 { return null } local rhs2 = JsonFragBox.read_int_after(s, kv22 + 8); if rhs2 == null { return null } // then Return(Int B) - local kth2 = s.indexOf("\"then\":", k_if2); if kth2 < 0 { return null } - local rt2 = s.indexOf("\"type\":\"Return\"", kth2); if rt2 < 0 { return null } - local ti23 = s.indexOf("\"type\":\"Int\"", rt2); if ti23 < 0 { return null } - local kv23 = s.indexOf("\"value\":", ti23); if kv23 < 0 { return null } + local kth2 = JsonFragBox.index_of_from(s, "\"then\":", k_if2); if kth2 < 0 { return null } + local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth2); if rt2 < 0 { return null } + local ti23 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2); if ti23 < 0 { return null } + local kv23 = JsonFragBox.index_of_from(s, "\"value\":", ti23); if kv23 < 0 { return null } local bval = JsonFragBox.read_int_after(s, kv23 + 8); if bval == null { return null } // else Return(Int C) - local kel2 = s.indexOf("\"else\":", k_if2); if kel2 < 0 { return null } - local rt3 = s.indexOf("\"type\":\"Return\"", kel2); if rt3 < 0 { return null } - local ti24 = s.indexOf("\"type\":\"Int\"", rt3); if ti24 < 0 { return null } - local kv24 = s.indexOf("\"value\":", ti24); if kv24 < 0 { return null } + local kel2 = JsonFragBox.index_of_from(s, "\"else\":", k_if2); if kel2 < 0 { return null } + local rt3 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kel2); if rt3 < 0 { return null } + local ti24 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt3); if ti24 < 0 { return null } + 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) diff --git a/lang/src/mir/builder/internal/lower_if_then_else_following_return_box.hako b/lang/src/mir/builder/internal/lower_if_then_else_following_return_box.hako index 52fd2abf..83ed596d 100644 --- a/lang/src/mir/builder/internal/lower_if_then_else_following_return_box.hako +++ b/lang/src/mir/builder/internal/lower_if_then_else_following_return_box.hako @@ -10,29 +10,29 @@ static box LowerIfThenElseFollowingReturnBox { try_lower(program_json) { local s = "" + program_json // If with Compare(Int,Int) - local k_if = s.indexOf("\"type\":\"If\"") + local k_if = JsonFragBox.index_of_from(s, "\"type\":\"If\"", 0) if k_if < 0 { return null } - 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 { return null } - local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null } + 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 } // LHS/RHS ints - local klhs = s.indexOf("\"lhs\":{", k_cmp); if klhs < 0 { return null } - local ti1 = s.indexOf("\"type\":\"Int\"", klhs); if ti1 < 0 { return null } - { local kv = s.indexOf("\"value\":", ti1); if kv < 0 { return null }; var lhs_val = JsonFragBox.read_int_after(s, kv + 8); if lhs_val == null { return null } } - local krhs = s.indexOf("\"rhs\":{", k_cmp); if krhs < 0 { return null } - local ti2 = s.indexOf("\"type\":\"Int\"", krhs); if ti2 < 0 { return null } - { local kv2 = s.indexOf("\"value\":", ti2); if kv2 < 0 { return null }; var rhs_val = JsonFragBox.read_int_after(s, kv2 + 8); if rhs_val == null { return null } } + 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 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 } } // then: Return(Int) - local kth = s.indexOf("\"then\":", k_if); if kth < 0 { return null } - local rt = s.indexOf("\"type\":\"Return\"", kth); if rt < 0 { return null } - local ti3 = s.indexOf("\"type\":\"Int\"", rt); if ti3 < 0 { return null } - { local kv3 = s.indexOf("\"value\":", ti3); if kv3 < 0 { return null }; var then_val = JsonFragBox.read_int_after(s, kv3 + 8); if then_val == null { return null } } + 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 } } // else is omitted → following Return(Int) in Program body - local k_after = s.indexOf("\"type\":\"Return\"", k_if + 1); if k_after < 0 { return null } - local ti4 = s.indexOf("\"type\":\"Int\"", k_after); if ti4 < 0 { return null } - { local kv4 = s.indexOf("\"value\":", ti4); if kv4 < 0 { return null }; var else_val = JsonFragBox.read_int_after(s, kv4 + 8); if else_val == null { return null } } + 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 } } // Build MIR(JSON) local b0 = new ArrayBox() diff --git a/lang/src/mir/builder/internal/lower_loop_count_param_box.hako b/lang/src/mir/builder/internal/lower_loop_count_param_box.hako index 0f339d9f..ba0aa969 100644 --- a/lang/src/mir/builder/internal/lower_loop_count_param_box.hako +++ b/lang/src/mir/builder/internal/lower_loop_count_param_box.hako @@ -12,27 +12,27 @@ static box LowerLoopCountParamBox { local s = "" + program_json // Discover loop variable name from Compare first // We'll accept either lhs Var(name) or rhs Var(name) - local k_loop = s.indexOf("\"type\":\"Loop\"", 0) + local k_loop = JsonFragBox.index_of_from(s, "\"type\":\"Loop\"", 0) if k_loop < 0 { return null } - local k_cmp = s.indexOf("\"type\":\"Compare\"", k_loop) + local k_cmp = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", k_loop) if k_cmp < 0 { return null } local varname = LoopScanBox.find_loop_var_name(s, k_cmp) if varname == null { return null } // Local = (Int init | Var initName) - local k_local_i = s.indexOf("\"type\":\"Local\"") + local k_local_i = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", 0) if k_local_i < 0 { return null } - if s.indexOf("\"name\":\"" + varname + "\"", k_local_i) < 0 { return null } + if JsonFragBox.index_of_from(s, "\"name\":\"" + varname + "\"", k_local_i) < 0 { return null } local init = null { - local k_init_int = s.indexOf("\"type\":\"Int\"", k_local_i) - local k_loop_next = s.indexOf("\"type\":\"Loop\"", k_local_i) + local k_init_int = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_local_i) + local k_loop_next = JsonFragBox.index_of_from(s, "\"type\":\"Loop\"", k_local_i) if k_init_int >= 0 && (k_loop_next < 0 || k_init_int < k_loop_next) { - local kv_i = s.indexOf("\"value\":", k_init_int); if kv_i >= 0 { init = JsonFragBox.read_int_after(s, kv_i + 8) } + local kv_i = JsonFragBox.index_of_from(s, "\"value\":", k_init_int); if kv_i >= 0 { init = JsonFragBox.read_int_after(s, kv_i + 8) } } else { - local k_init_var = s.indexOf("\"type\":\"Var\"", k_local_i) + local k_init_var = JsonFragBox.index_of_from(s, "\"type\":\"Var\"", k_local_i) if k_init_var >= 0 && (k_loop_next < 0 || k_init_var < k_loop_next) { - local kn_i = s.indexOf("\"name\":\"", k_init_var); if kn_i < 0 { return null } + local kn_i = JsonFragBox.index_of_from(s, "\"name\":\"", k_init_var); if kn_i < 0 { return null } local vname = JsonFragBox.read_string_after(s, kn_i) if vname != null { init = PatternUtilBox.find_local_int_before(s, vname, k_local_i) } } @@ -41,22 +41,22 @@ static box LowerLoopCountParamBox { if init == null { return null } // Loop Compare normalize: accept < / <= / > / >= with Var(varname) on either side // op: accept '<'/'<=' with i on lhs; '>'/'>=' with i on lhs (descending); swapped '>'/'>=' with i on rhs (ascending) - local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null } + local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_cmp); if k_op < 0 { return null } local op = JsonFragBox.read_string_after(s, k_op + 5) if op == null { return null } - local has_lhs_i = s.indexOf("\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0 - local has_rhs_i = s.indexOf("\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0 + local has_lhs_i = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0 + local has_rhs_i = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0 if !has_lhs_i && !has_rhs_i { return null } local cmp = null local limit = null if has_lhs_i { // rhs Int/Var → resolve limit - local k_rhs = s.indexOf("\"rhs\":{", k_cmp); if k_rhs < 0 { return null } - local k_lim_t = s.indexOf("\"type\":\"Int\"", k_rhs) - if k_lim_t >= 0 { local kv = s.indexOf("\"value\":", k_lim_t); if kv >= 0 { limit = JsonFragBox.read_int_after(s, kv + 8) } } + local k_rhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp); if k_rhs < 0 { return null } + local k_lim_t = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhs) + if k_lim_t >= 0 { local kv = JsonFragBox.index_of_from(s, "\"value\":", k_lim_t); if kv >= 0 { limit = JsonFragBox.read_int_after(s, kv + 8) } } else { - local k_rv = s.indexOf("\"type\":\"Var\"", k_rhs); if k_rv < 0 { return null } - local kn = s.indexOf("\"name\":\"", k_rhs); if kn < 0 { return null } + local k_rv = JsonFragBox.index_of_from(s, "\"type\":\"Var\"", k_rhs); if k_rv < 0 { return null } + local kn = JsonFragBox.index_of_from(s, "\"name\":\"", k_rhs); if kn < 0 { return null } local lname = JsonFragBox.read_string_after(s, kn); if lname == null { return null } limit = PatternUtilBox.find_local_int_before(s, lname, k_cmp) } @@ -69,12 +69,12 @@ static box LowerLoopCountParamBox { limit = norm.substring(cpos+1, norm.length()) } else { if op != ">" && op != ">=" && op != "<" && op != "<=" && op != "!=" { return null } - local k_lhs = s.indexOf("\"lhs\":{", k_cmp); if k_lhs < 0 { return null } - local k_lim_t2 = s.indexOf("\"type\":\"Int\"", k_lhs) - if k_lim_t2 >= 0 { local kv2 = s.indexOf("\"value\":", k_lim_t2); if kv2 >= 0 { limit = JsonFragBox.read_int_after(s, kv2 + 8) } } + local k_lhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp); if k_lhs < 0 { return null } + local k_lim_t2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhs) + if k_lim_t2 >= 0 { local kv2 = JsonFragBox.index_of_from(s, "\"value\":", k_lim_t2); if kv2 >= 0 { limit = JsonFragBox.read_int_after(s, kv2 + 8) } } else { - local k_lv = s.indexOf("\"type\":\"Var\"", k_lhs); if k_lv < 0 { return null } - local kn3 = s.indexOf("\"name\":\"", k_lhs); if kn3 < 0 { return null } + local k_lv = JsonFragBox.index_of_from(s, "\"type\":\"Var\"", k_lhs); if k_lv < 0 { return null } + local kn3 = JsonFragBox.index_of_from(s, "\"name\":\"", k_lhs); if kn3 < 0 { return null } local lname3 = JsonFragBox.read_string_after(s, kn3); if lname3 == null { return null } limit = PatternUtilBox.find_local_int_before(s, lname3, k_cmp) } @@ -86,27 +86,27 @@ static box LowerLoopCountParamBox { limit = norm2.substring(cpos2+1, norm2.length()) } // Body increment: Local i = Binary('+', Var i, Int step) - local k_body_i = s.indexOf("\"name\":\"" + varname + "\"", k_loop) + local k_body_i = JsonFragBox.index_of_from(s, "\"name\":\"" + varname + "\"", k_loop) if k_body_i < 0 { return null } - local k_bop = s.indexOf("\"type\":\"Binary\"", k_body_i) + local k_bop = JsonFragBox.index_of_from(s, "\"type\":\"Binary\"", k_body_i) if k_bop < 0 { return null } // Body increment: Local i = Binary(op '+' or '-', Var i, (Int step | Var stepName)) - local bop_plus = (s.indexOf("\"op\":\"+\"", k_bop) >= 0) - local bop_minus = (s.indexOf("\"op\":\"-\"", k_bop) >= 0) + local bop_plus = (JsonFragBox.index_of_from(s, "\"op\":\"+\"", k_bop) >= 0) + local bop_minus = (JsonFragBox.index_of_from(s, "\"op\":\"-\"", k_bop) >= 0) if (!bop_plus && !bop_minus) { return null } - if s.indexOf("\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_bop) < 0 { return null } + if JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_bop) < 0 { return null } local step = null // Prefer rhs Int if present; otherwise try rhs Var and reverse-lookup its Local Int { - local k_rhsb = s.indexOf("\"rhs\":{", k_bop); if k_rhsb < 0 { return null } - local k_t_int = s.indexOf("\"type\":\"Int\"", k_rhsb) + local k_rhsb = JsonFragBox.index_of_from(s, "\"rhs\":{", k_bop); if k_rhsb < 0 { return null } + local k_t_int = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhsb) if k_t_int >= 0 { - local kvs = s.indexOf("\"value\":", k_t_int); if kvs >= 0 { step = JsonFragBox.read_int_after(s, kvs + 8) } + local kvs = JsonFragBox.index_of_from(s, "\"value\":", k_t_int); if kvs >= 0 { step = JsonFragBox.read_int_after(s, kvs + 8) } } else { - local k_t_var = s.indexOf("\"type\":\"Var\"", k_rhsb) + local k_t_var = JsonFragBox.index_of_from(s, "\"type\":\"Var\"", k_rhsb) if k_t_var < 0 { return null } - local kns = s.indexOf("\"name\":\"", k_rhsb); if kns < 0 { return null } + local kns = JsonFragBox.index_of_from(s, "\"name\":\"", k_rhsb); if kns < 0 { return null } local vname = JsonFragBox.read_string_after(s, kns); if vname == null { return null } step = PatternUtilBox.find_local_int_before(s, vname, k_bop) } diff --git a/lang/src/mir/builder/internal/lower_loop_simple_box.hako b/lang/src/mir/builder/internal/lower_loop_simple_box.hako index 0c08758d..43d8226b 100644 --- a/lang/src/mir/builder/internal/lower_loop_simple_box.hako +++ b/lang/src/mir/builder/internal/lower_loop_simple_box.hako @@ -12,38 +12,38 @@ static box LowerLoopSimpleBox { try_lower(program_json) { local s = "" + program_json // Find Loop with cond Compare and normalize to canonical (<) with dynamic var name - local k_loop = s.indexOf("\"type\":\"Loop\"") + local k_loop = JsonFragBox.index_of_from(s, "\"type\":\"Loop\"", 0) if k_loop < 0 { return null } - local k_cmp = s.indexOf("\"type\":\"Compare\"", k_loop) + local k_cmp = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", k_loop) if k_cmp < 0 { return null } // discover loop var name from cond (lhs or rhs Var) local varname = LoopScanBox.find_loop_var_name(s, k_cmp) if varname == null { return null } // op: accept '<' / '<=' as-is, '!=' (with var on lhs) as '<', and swapped '>' / '>=' (with var on rhs) - local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null } + local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_cmp); if k_op < 0 { return null } local op = JsonFragBox.read_string_after(s, k_op + 5) if op == null { return null } // Determine where Var(varname) is and extract the Int from the opposite side - local has_lhs_i = s.indexOf("\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0 - local has_rhs_i = s.indexOf("\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0 + local has_lhs_i = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0 + local has_rhs_i = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0 if !has_lhs_i && !has_rhs_i { return null } local swapped = 0 local limit = null if has_lhs_i { // rhs Int value - local k_rhs = s.indexOf("\"rhs\":{", k_cmp); if k_rhs < 0 { return null } - local k_ti = s.indexOf("\"type\":\"Int\"", k_rhs); if k_ti < 0 { return null } - local k_v = s.indexOf("\"value\":", k_ti); if k_v < 0 { return null } + local k_rhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp); if k_rhs < 0 { return null } + local k_ti = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhs); if k_ti < 0 { return null } + local k_v = JsonFragBox.index_of_from(s, "\"value\":", k_ti); if k_v < 0 { return null } limit = JsonFragBox.read_int_after(s, k_v + 8) if limit == null { return null } } else { // Var is on rhs; lhs must be Int swapped = 1 - local k_lhs = s.indexOf("\"lhs\":{", k_cmp); if k_lhs < 0 { return null } - local k_ti2 = s.indexOf("\"type\":\"Int\"", k_lhs); if k_ti2 < 0 { return null } - local k_v2 = s.indexOf("\"value\":", k_ti2); if k_v2 < 0 { return null } + local k_lhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp); if k_lhs < 0 { return null } + local k_ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhs); if k_ti2 < 0 { return null } + local k_v2 = JsonFragBox.index_of_from(s, "\"value\":", k_ti2); if k_v2 < 0 { return null } limit = JsonFragBox.read_int_after(s, k_v2 + 8) if limit == null { return null } } diff --git a/lang/src/mir/builder/internal/lower_loop_sum_bc_box.hako b/lang/src/mir/builder/internal/lower_loop_sum_bc_box.hako index 7ba28826..8ad2a9bc 100644 --- a/lang/src/mir/builder/internal/lower_loop_sum_bc_box.hako +++ b/lang/src/mir/builder/internal/lower_loop_sum_bc_box.hako @@ -21,19 +21,19 @@ static box LowerLoopSumBcBox { print("[sum_bc] enter lower") } // Loop and Compare normalize to canonical (<) with dynamic var name - local k_loop = s.indexOf("\"type\":\"Loop\"") + local k_loop = JsonFragBox.index_of_from(s, "\"type\":\"Loop\"", 0) if k_loop < 0 { return null } - local k_cmp = s.indexOf("\"type\":\"Compare\"", k_loop) + local k_cmp = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", k_loop) if k_cmp < 0 { return null } // discover loop var name from cond (lhs or rhs Var) 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) } } } if varname == null { return null } @@ -41,27 +41,27 @@ static box LowerLoopSumBcBox { print("[sum_bc] var=" + varname) } // op: accept '<'/'<=' with var on lhs; also accept swapped '>'/'>=' with var on rhs - local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null } + local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_cmp); if k_op < 0 { return null } local op = JsonFragBox.read_string_after(s, k_op + 5) if op == null { return null } - local has_lhs_i = s.indexOf("\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0 - local has_rhs_i = s.indexOf("\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0 + local has_lhs_i = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0 + local has_rhs_i = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0 if !has_lhs_i && !has_rhs_i { return null } local limit = null if has_lhs_i { if op != "<" && op != "<=" { return null } // rhs Int limit - local k_rhs = s.indexOf("\"rhs\":{", k_cmp); if k_rhs < 0 { return null } - local k_ti = s.indexOf("\"type\":\"Int\"", k_rhs); if k_ti < 0 { return null } - local kv = s.indexOf("\"value\":", k_ti); if kv < 0 { return null } + local k_rhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp); if k_rhs < 0 { return null } + local k_ti = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhs); if k_ti < 0 { return null } + local kv = JsonFragBox.index_of_from(s, "\"value\":", k_ti); if kv < 0 { return null } limit = JsonFragBox.read_int_after(s, kv + 8); if limit == null { return null } if op == "<=" { limit = StringHelpers.int_to_str(JsonFragBox._str_to_int(limit) + 1) } } else { // swapped: Int on lhs, Var i on rhs, op should be '>' or '>=' if op != ">" && op != ">=" { return null } - local k_lhs = s.indexOf("\"lhs\":{", k_cmp); if k_lhs < 0 { return null } - local k_ti2 = s.indexOf("\"type\":\"Int\"", k_lhs); if k_ti2 < 0 { return null } - local kv2 = s.indexOf("\"value\":", k_ti2); if kv2 < 0 { return null } + local k_lhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp); if k_lhs < 0 { return null } + local k_ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhs); if k_ti2 < 0 { return null } + local kv2 = JsonFragBox.index_of_from(s, "\"value\":", k_ti2); if kv2 < 0 { return null } limit = JsonFragBox.read_int_after(s, kv2 + 8); if limit == null { return null } if op == ">=" { limit = StringHelpers.int_to_str(JsonFragBox._str_to_int(limit) + 1) } } @@ -69,22 +69,24 @@ static box LowerLoopSumBcBox { // Break sentinel: If(cond Compare var==X or X==var) then Break local break_value = null { - local kb = s.indexOf("\"type\":\"Break\"", k_loop) + local kb = JsonFragBox.index_of_from(s, "\"type\":\"Break\"", k_loop) if kb >= 0 { // Find nearest previous Compare and grab rhs Int local kbc = s.lastIndexOf("\"type\":\"Compare\"", kb) if kbc >= 0 { // Ensure op=="==" and lhs Var i - local kop = s.indexOf("\"op\":", kbc); local bop = null; if kop >= 0 { bop = JsonFragBox.read_string_after(s, kop + 5) } + 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 = s.indexOf("\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kbc) >= 0 - local rhs_i = s.indexOf("\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kbc) >= 0 + 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 kbi = s.indexOf("\"type\":\"Int\"", s.indexOf("\"rhs\":{", kbc)) - if kbi >= 0 { local kvb = s.indexOf("\"value\":", kbi); if kvb >= 0 { break_value = JsonFragBox.read_int_after(s, kvb + 8) } } + 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 kbi2 = s.indexOf("\"type\":\"Int\"", s.indexOf("\"lhs\":{", kbc)) - if kbi2 >= 0 { local kvb2 = s.indexOf("\"value\":", kbi2); if kvb2 >= 0 { break_value = JsonFragBox.read_int_after(s, kvb2 + 8) } } + 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] @@ -92,11 +94,11 @@ static box LowerLoopSumBcBox { // Fallback: try local JsonFragBox-based extraction near kbc if break_value == null { // Read Int from lhs or rhs around kbc - local k_rhsb = s.indexOf("\"rhs\":{", kbc); local k_lhsb = s.indexOf("\"lhs\":{", kbc) - if k_rhsb >= 0 && s.indexOf("\"type\":\"Int\"", k_rhsb) >= 0 { - local kvi = s.indexOf("\"value\":", s.indexOf("\"type\":\"Int\"", k_rhsb)); if kvi >= 0 { break_value = JsonFragBox.read_int_after(s, kvi + 8) } - } else if k_lhsb >= 0 && s.indexOf("\"type\":\"Int\"", k_lhsb) >= 0 { - local kvj = s.indexOf("\"value\":", s.indexOf("\"type\":\"Int\"", k_lhsb)); if kvj >= 0 { break_value = JsonFragBox.read_int_after(s, kvj + 8) } + 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) } } } } @@ -106,31 +108,33 @@ static box LowerLoopSumBcBox { // Continue sentinel: If(cond Compare var==Y or Y==var) then Continue local skip_value = null { - local kc = s.indexOf("\"type\":\"Continue\"", k_loop) + local kc = JsonFragBox.index_of_from(s, "\"type\":\"Continue\"", k_loop) if kc >= 0 { local kcc = s.lastIndexOf("\"type\":\"Compare\"", kc) if kcc >= 0 { - local kop2 = s.indexOf("\"op\":", kcc); local cop = null; if kop2 >= 0 { cop = JsonFragBox.read_string_after(s, kop2 + 5) } + 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 = s.indexOf("\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kcc) >= 0 - local rhs_i2 = s.indexOf("\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kcc) >= 0 + 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 kci = s.indexOf("\"type\":\"Int\"", s.indexOf("\"rhs\":{", kcc)) - if kci >= 0 { local kvs = s.indexOf("\"value\":", kci); if kvs >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs + 8) } } + 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 kci2 = s.indexOf("\"type\":\"Int\"", s.indexOf("\"lhs\":{", kcc)) - if kci2 >= 0 { local kvs2 = s.indexOf("\"value\":", kci2); if kvs2 >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs2 + 8) } } + 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_rhsb2 = s.indexOf("\"rhs\":{", kcc); local k_lhsb2 = s.indexOf("\"lhs\":{", kcc) - if k_rhsb2 >= 0 && s.indexOf("\"type\":\"Int\"", k_rhsb2) >= 0 { - local kvs = s.indexOf("\"value\":", s.indexOf("\"type\":\"Int\"", k_rhsb2)); if kvs >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs + 8) } - } else if k_lhsb2 >= 0 && s.indexOf("\"type\":\"Int\"", k_lhsb2) >= 0 { - local kvs2 = s.indexOf("\"value\":", s.indexOf("\"type\":\"Int\"", k_lhsb2)); if kvs2 >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs2 + 8) } + 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) } } } } diff --git a/lang/src/mir/builder/internal/lower_method_array_get_set_box.hako b/lang/src/mir/builder/internal/lower_method_array_get_set_box.hako index 572156f6..6a1dd2c9 100644 --- a/lang/src/mir/builder/internal/lower_method_array_get_set_box.hako +++ b/lang/src/mir/builder/internal/lower_method_array_get_set_box.hako @@ -5,8 +5,8 @@ static box LowerMethodArrayGetSetBox { try_lower(program_json) { if program_json == null { return null } local s = "" + program_json - if s.indexOf("\"type\":\"New\"") < 0 { return null } - if s.indexOf("\"class\":\"ArrayBox\"") < 0 { return null } + if JsonFragBox.index_of_from(s, "\"type\":\"New\"", 0) < 0 { return null } + if JsonFragBox.index_of_from(s, "\"class\":\"ArrayBox\"", 0) < 0 { return null } // Reverse-lookup (safe subset): prefer Local(Int) for index, Local(String) for value local n = s.length() local idx = PatternUtilBox.find_any_local_int_before(s, n) diff --git a/lang/src/mir/builder/internal/lower_method_array_push_box.hako b/lang/src/mir/builder/internal/lower_method_array_push_box.hako index 99c37d00..89141fb2 100644 --- a/lang/src/mir/builder/internal/lower_method_array_push_box.hako +++ b/lang/src/mir/builder/internal/lower_method_array_push_box.hako @@ -5,8 +5,8 @@ static box LowerMethodArrayPushBox { try_lower(program_json) { if program_json == null { return null } local s = "" + program_json - if s.indexOf("\"type\":\"New\"") < 0 { return null } - if s.indexOf("\"class\":\"ArrayBox\"") < 0 { return null } + if JsonFragBox.index_of_from(s, "\"type\":\"New\"", 0) < 0 { return null } + if JsonFragBox.index_of_from(s, "\"class\":\"ArrayBox\"", 0) < 0 { return null } // Reverse-lookup (safe subset): prefer Local(Int) for push values when present local n = s.length() local p1 = PatternUtilBox.find_any_local_int_before(s, n); if p1 == null { p1 = "1" } diff --git a/lang/src/mir/builder/internal/lower_method_array_size_box.hako b/lang/src/mir/builder/internal/lower_method_array_size_box.hako index 8243e3ca..c67f3f80 100644 --- a/lang/src/mir/builder/internal/lower_method_array_size_box.hako +++ b/lang/src/mir/builder/internal/lower_method_array_size_box.hako @@ -5,8 +5,8 @@ static box LowerMethodArraySizeBox { try_lower(program_json) { if program_json == null { return null } local s = "" + program_json - if s.indexOf("\"type\":\"New\"") < 0 { return null } - if s.indexOf("\"class\":\"ArrayBox\"") < 0 { return null } + if JsonFragBox.index_of_from(s, "\"type\":\"New\"", 0) < 0 { return null } + if JsonFragBox.index_of_from(s, "\"class\":\"ArrayBox\"", 0) < 0 { return null } // Emit MIR v1 JSON: new ArrayBox -> r1, size(r1) -> r2, const 0 -> r3, ret r3 local json = "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[{\"name\":\"main\",\"blocks\":[{\"id\":0,\"instructions\":[" + "{\"op\":\"mir_call\",\"dst\":1,\"mir_call\":{\"callee\":{\"type\":\"Constructor\",\"box_type\":\"ArrayBox\"},\"args\":[],\"effects\":[]}}," + @@ -16,4 +16,3 @@ static box LowerMethodArraySizeBox { return json } } - diff --git a/lang/src/mir/builder/internal/lower_method_map_get_set_box.hako b/lang/src/mir/builder/internal/lower_method_map_get_set_box.hako index 58e5a88b..05ef9397 100644 --- a/lang/src/mir/builder/internal/lower_method_map_get_set_box.hako +++ b/lang/src/mir/builder/internal/lower_method_map_get_set_box.hako @@ -5,8 +5,8 @@ static box LowerMethodMapGetSetBox { try_lower(program_json) { if program_json == null { return null } local s = "" + program_json - if s.indexOf("\"type\":\"New\"") < 0 { return null } - if s.indexOf("\"class\":\"MapBox\"") < 0 { return null } + if JsonFragBox.index_of_from(s, "\"type\":\"New\"", 0) < 0 { return null } + if JsonFragBox.index_of_from(s, "\"class\":\"MapBox\"", 0) < 0 { return null } // Reverse-lookup (safe subset): prefer Local(String) for key, Local(Int) for value local n = s.length() local key = PatternUtilBox.find_any_local_string_before(s, n) diff --git a/lang/src/mir/builder/internal/lower_method_map_size_box.hako b/lang/src/mir/builder/internal/lower_method_map_size_box.hako index 0c77940c..1eab704d 100644 --- a/lang/src/mir/builder/internal/lower_method_map_size_box.hako +++ b/lang/src/mir/builder/internal/lower_method_map_size_box.hako @@ -4,8 +4,8 @@ static box LowerMethodMapSizeBox { try_lower(program_json) { if program_json == null { return null } local s = "" + program_json - if s.indexOf("\"type\":\"New\"") < 0 { return null } - if s.indexOf("\"class\":\"MapBox\"") < 0 { return null } + if JsonFragBox.index_of_from(s, "\"type\":\"New\"", 0) < 0 { return null } + if JsonFragBox.index_of_from(s, "\"class\":\"MapBox\"", 0) < 0 { return null } local json = "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[{\"name\":\"main\",\"blocks\":[{\"id\":0,\"instructions\":[" + "{\"op\":\"mir_call\",\"dst\":1,\"mir_call\":{\"callee\":{\"type\":\"Constructor\",\"box_type\":\"MapBox\"},\"args\":[],\"effects\":[]}}," + "{\"op\":\"mir_call\",\"dst\":2,\"mir_call\":{\"callee\":{\"type\":\"Method\",\"box_name\":\"MapBox\",\"method\":\"size\",\"receiver\":1},\"args\":[],\"effects\":[]}}," + @@ -14,4 +14,3 @@ static box LowerMethodMapSizeBox { return json } } - diff --git a/lang/src/mir/builder/internal/lower_newbox_constructor_box.hako b/lang/src/mir/builder/internal/lower_newbox_constructor_box.hako index 431d1756..ce61baf8 100644 --- a/lang/src/mir/builder/internal/lower_newbox_constructor_box.hako +++ b/lang/src/mir/builder/internal/lower_newbox_constructor_box.hako @@ -7,11 +7,11 @@ static box LowerNewboxConstructorBox { if program_json == null { return null } local s = "" + program_json // Quick pattern check - if s.indexOf("\"type\":\"New\"") < 0 { return null } + if JsonFragBox.index_of_from(s, "\"type\":\"New\"", 0) < 0 { return null } // Find class name (minimal scan) local cls = null - if s.indexOf("\"class\":\"ArrayBox\"") >= 0 { cls = "ArrayBox" } - else { if s.indexOf("\"class\":\"MapBox\"") >= 0 { cls = "MapBox" } } + if JsonFragBox.index_of_from(s, "\"class\":\"ArrayBox\"", 0) >= 0 { cls = "ArrayBox" } + else { if JsonFragBox.index_of_from(s, "\"class\":\"MapBox\"", 0) >= 0 { cls = "MapBox" } } if cls == null { return null } // Only accept known minimal boxes if !(cls == "ArrayBox" || cls == "MapBox") { return null } diff --git a/lang/src/mir/builder/internal/lower_return_binop_box.hako b/lang/src/mir/builder/internal/lower_return_binop_box.hako index a5f6b31c..96f44c46 100644 --- a/lang/src/mir/builder/internal/lower_return_binop_box.hako +++ b/lang/src/mir/builder/internal/lower_return_binop_box.hako @@ -5,34 +5,34 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox static box LowerReturnBinOpBox { try_lower(program_json) { local s = "" + program_json - local k_ret = s.indexOf("\"type\":\"Return\"") + local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0) if k_ret < 0 { return null } - 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 { return null } // op - local k_op = s.indexOf("\"op\":", k_bin) + local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_bin) if k_op < 0 { return null } local op = JsonFragBox.read_string_after(s, k_op + 5) if op == null { return null } if !(op == "+" || op == "-" || op == "*" || op == "/") { return null } // lhs/rhs object starts - local klhs = s.indexOf("\"lhs\":{", k_bin) - local krhs = s.indexOf("\"rhs\":{", k_bin) + local klhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_bin) + local krhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_bin) if klhs < 0 { return null } // strictly ensure lhs node is Int by bounding search before rhs start - local ti = s.indexOf("\"type\":\"Int\"", klhs) + local ti = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", klhs) if ti < 0 { return null } if krhs >= 0 && ti >= krhs { return null } - local kv_lhs = s.indexOf("\"value\":", ti) + local kv_lhs = JsonFragBox.index_of_from(s, "\"value\":", ti) if kv_lhs < 0 { return null } if krhs >= 0 && kv_lhs >= krhs { return null } local lhs_val = JsonFragBox.read_int_after(s, kv_lhs + 8) if lhs_val == null { return null } // rhs int if krhs < 0 { return null } - local ti2 = s.indexOf("\"type\":\"Int\"", krhs) + local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", krhs) if ti2 < 0 { return null } - local kv_rhs = s.indexOf("\"value\":", ti2) + local kv_rhs = JsonFragBox.index_of_from(s, "\"value\":", ti2) if kv_rhs < 0 { return null } local rhs_val = JsonFragBox.read_int_after(s, kv_rhs + 8) if rhs_val == null { return null } diff --git a/lang/src/mir/builder/internal/lower_return_binop_varint_box.hako b/lang/src/mir/builder/internal/lower_return_binop_varint_box.hako index d4016223..1155b28c 100644 --- a/lang/src/mir/builder/internal/lower_return_binop_varint_box.hako +++ b/lang/src/mir/builder/internal/lower_return_binop_varint_box.hako @@ -10,26 +10,27 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox static box LowerReturnBinOpVarIntBox { try_lower(program_json) { local s = "" + program_json - local k_ret = s.indexOf("\"type\":\"Return\"") + local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0) if k_ret < 0 { return null } - 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 { return null } - local k_op = s.indexOf("\"op\":", k_bin) + local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_bin) if k_op < 0 { return null } local op = JsonFragBox.read_string_after(s, k_op + 5) if op == null { return null } - if !(op == "+" || op == "-" || op == "*" || op == "/") { return null } + // Map op symbol to MIR op_kind via shared util + local kind = PatternUtilBox.map_binop(op); if kind == null { return null } // Try Var + Int - local klhs_var = s.indexOf("\"lhs\":{\"type\":\"Var\"", k_bin) - local krhs_int = s.indexOf("\"rhs\":{\"type\":\"Int\"", k_bin) + local klhs_var = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\"", k_bin) + local krhs_int = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Int\"", k_bin) local var_name = null local rhs_val = null if klhs_var >= 0 && krhs_int >= 0 { - local k_name = s.indexOf("\"name\":", klhs_var); if k_name < 0 { return null } + local k_name = JsonFragBox.index_of_from(s, "\"name\":", klhs_var); if k_name < 0 { return null } var_name = JsonFragBox.read_string_after(s, k_name + 7) - local kvi = s.indexOf("\"type\":\"Int\"", krhs_int) + local kvi = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", krhs_int) if kvi >= 0 { - local kv = s.indexOf("\"value\":", kvi); if kv < 0 { return null } + local kv = JsonFragBox.index_of_from(s, "\"value\":", kvi); if kv < 0 { return null } rhs_val = JsonFragBox.read_int_after(s, kv + 8) } if var_name != null && rhs_val != null { @@ -38,7 +39,7 @@ static box LowerReturnBinOpVarIntBox { 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(op == "+" ? "Add" : (op == "-" ? "Sub" : (op == "*" ? "Mul" : "Div")), 1, 2, 3)) + 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)) @@ -46,17 +47,17 @@ static box LowerReturnBinOpVarIntBox { } } // Try Int + Var - local klhs_int = s.indexOf("\"lhs\":{\"type\":\"Int\"", k_bin) - local krhs_var = s.indexOf("\"rhs\":{\"type\":\"Var\"", k_bin) + local klhs_int = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Int\"", k_bin) + local krhs_var = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\"", k_bin) var_name = null local lhs_val = null if klhs_int >= 0 && krhs_var >= 0 { - local kvi2 = s.indexOf("\"type\":\"Int\"", klhs_int) + local kvi2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", klhs_int) if kvi2 >= 0 { - local kv2 = s.indexOf("\"value\":", kvi2); if kv2 < 0 { return null } + local kv2 = JsonFragBox.index_of_from(s, "\"value\":", kvi2); if kv2 < 0 { return null } lhs_val = JsonFragBox.read_int_after(s, kv2 + 8) } - local k_name2 = s.indexOf("\"name\":", krhs_var); if k_name2 < 0 { return null } + local k_name2 = JsonFragBox.index_of_from(s, "\"name\":", krhs_var); if k_name2 < 0 { return null } var_name = JsonFragBox.read_string_after(s, k_name2 + 7) if lhs_val != null && var_name != null { local var_val2 = PatternUtilBox.find_local_int_before(s, var_name, k_ret) @@ -64,7 +65,7 @@ static box LowerReturnBinOpVarIntBox { 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(op == "+" ? "Add" : (op == "-" ? "Sub" : (op == "*" ? "Mul" : "Div")), 1, 2, 3)) + 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)) diff --git a/lang/src/mir/builder/internal/lower_return_binop_varvar_box.hako b/lang/src/mir/builder/internal/lower_return_binop_varvar_box.hako index e6c302db..a63c8a47 100644 --- a/lang/src/mir/builder/internal/lower_return_binop_varvar_box.hako +++ b/lang/src/mir/builder/internal/lower_return_binop_varvar_box.hako @@ -7,20 +7,20 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox static box LowerReturnBinOpVarVarBox { try_lower(program_json){ local s = "" + program_json - local k_ret = s.indexOf("\"type\":\"Return\""); if k_ret < 0 { return null } - local k_bin = s.indexOf("\"type\":\"Binary\"", k_ret); if k_bin < 0 { return null } - local k_op = s.indexOf("\"op\":", k_bin); if k_op < 0 { return null } + local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0); if k_ret < 0 { return null } + local k_bin = JsonFragBox.index_of_from(s, "\"type\":\"Binary\"", k_ret); if k_bin < 0 { return null } + local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_bin); if k_op < 0 { return null } local op = JsonFragBox.read_string_after(s, k_op + 5); if op == null { return null } - if !(op == "+" || op == "-" || op == "*" || op == "/") { return null } - local klhs = s.indexOf("\"lhs\":{\"type\":\"Var\"", k_bin); if klhs < 0 { return null } - local krhs = s.indexOf("\"rhs\":{\"type\":\"Var\"", k_bin); if krhs < 0 { return null } - local knl = s.indexOf("\"name\":", klhs); if knl < 0 { return null } + local kind = PatternUtilBox.map_binop(op); if kind == null { return null } + local klhs = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\"", k_bin); if klhs < 0 { return null } + local krhs = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\"", k_bin); if krhs < 0 { return null } + local knl = JsonFragBox.index_of_from(s, "\"name\":", klhs); if knl < 0 { return null } local lname = JsonFragBox.read_string_after(s, knl + 7); if lname == null { return null } - local knr = s.indexOf("\"name\":", krhs); if knr < 0 { return null } + local knr = JsonFragBox.index_of_from(s, "\"name\":", krhs); if knr < 0 { return null } 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(op == "+" ? "Add" : (op == "-" ? "Sub" : (op == "*" ? "Mul" : "Div")),1,2,3)); b0.push(MirSchemaBox.inst_ret(3)) + 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)) } diff --git a/lang/src/mir/builder/internal/lower_return_bool_box.hako b/lang/src/mir/builder/internal/lower_return_bool_box.hako index 85656004..a510e898 100644 --- a/lang/src/mir/builder/internal/lower_return_bool_box.hako +++ b/lang/src/mir/builder/internal/lower_return_bool_box.hako @@ -5,16 +5,16 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox static box LowerReturnBoolBox { try_lower(program_json) { local s = "" + program_json - local k_ret = s.indexOf("\"type\":\"Return\"") + local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0) if k_ret < 0 { return null } // Restrict to Return(expr=Bool …): require expr 開始直後に Bool が来る // 例: "expr":{"type":"Bool","value":true} - local k_expr = s.indexOf("\"expr\":", k_ret) + local k_expr = JsonFragBox.index_of_from(s, "\"expr\":", k_ret) if k_expr < 0 { return null } - local k_bool = s.indexOf("\"type\":\"Bool\"", k_expr) + local k_bool = JsonFragBox.index_of_from(s, "\"type\":\"Bool\"", k_expr) if k_bool < 0 { return null } // Ensure this Bool belongs to the same expr (次の '}' までに value があることを確認) - local k_val = s.indexOf("\"value\":", k_bool) + local k_val = JsonFragBox.index_of_from(s, "\"value\":", k_bool) if k_val < 0 { return null } local is_true = JsonFragBox.read_bool_after(s, k_val+8) if is_true == null { return null } diff --git a/lang/src/mir/builder/internal/lower_return_float_box.hako b/lang/src/mir/builder/internal/lower_return_float_box.hako index 2fb3248d..c4ded245 100644 --- a/lang/src/mir/builder/internal/lower_return_float_box.hako +++ b/lang/src/mir/builder/internal/lower_return_float_box.hako @@ -6,11 +6,11 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox static box LowerReturnFloatBox { try_lower(program_json) { local s = "" + program_json - local k_ret = s.indexOf("\"type\":\"Return\"") + local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0) if k_ret < 0 { return null } - local k_float = s.indexOf("\"type\":\"Float\"", k_ret) + local k_float = JsonFragBox.index_of_from(s, "\"type\":\"Float\"", k_ret) if k_float < 0 { return null } - local k_val = s.indexOf("\"value\":", k_float) + local k_val = JsonFragBox.index_of_from(s, "\"value\":", k_float) if k_val < 0 { return null } local fstr = JsonFragBox.read_float_after(s, k_val+8) if fstr == null { return null } diff --git a/lang/src/mir/builder/internal/lower_return_int_box.hako b/lang/src/mir/builder/internal/lower_return_int_box.hako index b57aee4d..c2793c71 100644 --- a/lang/src/mir/builder/internal/lower_return_int_box.hako +++ b/lang/src/mir/builder/internal/lower_return_int_box.hako @@ -5,14 +5,14 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox static box LowerReturnIntBox { try_lower(program_json) { local s = "" + program_json - local k_ret = s.indexOf("\"type\":\"Return\"") + local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0) if k_ret < 0 { return null } // Find expr object - local k_expr = s.indexOf("\"expr\":{", k_ret) + 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 = s.indexOf("\"type\":", k_type_start) + 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 @@ -28,9 +28,9 @@ static box LowerReturnIntBox { if k_type_val + 3 >= n { return null } if s.substring(k_type_val+3, k_type_val+4) != "\"" { return null } // Now extract the value - local k_int = s.indexOf("\"type\":\"Int\"", k_expr) + local k_int = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_expr) if k_int < 0 { return null } - local kv = s.indexOf("\"value\":", k_int); if kv < 0 { return null } + 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 } local debug_on = 0 diff --git a/lang/src/mir/builder/internal/lower_return_logical_box.hako b/lang/src/mir/builder/internal/lower_return_logical_box.hako index ee5783e4..e32a196d 100644 --- a/lang/src/mir/builder/internal/lower_return_logical_box.hako +++ b/lang/src/mir/builder/internal/lower_return_logical_box.hako @@ -11,7 +11,7 @@ static box LowerReturnLogicalBox { try_lower(program_json) { local s = "" + program_json - local k_ret = s.indexOf("\"type\":\"Return\"") + local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0) if k_ret < 0 { return null } local k_log = JsonFragBox.index_of_from(s, "\"type\":\"Logical\"", k_ret) if k_log < 0 { return null } diff --git a/lang/src/mir/builder/internal/lower_return_method_array_map_box.hako b/lang/src/mir/builder/internal/lower_return_method_array_map_box.hako index 5fb28056..cc65a5cb 100644 --- a/lang/src/mir/builder/internal/lower_return_method_array_map_box.hako +++ b/lang/src/mir/builder/internal/lower_return_method_array_map_box.hako @@ -8,12 +8,12 @@ using selfhost.vm.helpers.method_alias_policy as MethodAliasPolicy static box LowerReturnMethodArrayMapBox { try_lower(program_json) { local s = "" + program_json - local k_ret = s.indexOf("\"type\":\"Return\""); if k_ret < 0 { return null } - local k_m = s.indexOf("\"type\":\"Method\"", k_ret); if k_m < 0 { return null } + 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 } // receiver must be Var(name) - local k_recv = s.indexOf("\"recv\":{\"type\":\"Var\"", k_m); if k_recv < 0 { return null } + local k_recv = JsonFragBox.index_of_from(s, "\"recv\":{\"type\":\"Var\"", k_m); if k_recv < 0 { return null } local method = null - { local km = s.indexOf("\"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) } // Standardize: generate 'size' (len/length are accepted aliases at receiver) method = MethodAliasPolicy.normalize_size(method) // Allow basic methods @@ -23,91 +23,56 @@ static box LowerReturnMethodArrayMapBox { local b0 = new ArrayBox() // Receiver placeholder (Var resolve未実装のため 0 を置く) b0.push(MirSchemaBox.inst_const(1, 0)) - local k_args = s.indexOf("\"args\":", k_m) + local k_args = JsonFragBox.index_of_from(s, "\"args\":", k_m) local next_id = 2 if k_args >= 0 { // first arg: Int or Var(Int) - local k_i1 = s.indexOf("\"type\":\"Int\"", k_args) - local k_v1 = s.indexOf("\"type\":\"Var\"", k_args) + local k_i1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_args) + local k_v1 = JsonFragBox.index_of_from(s, "\"type\":\"Var\"", k_args) if k_i1 >= 0 && (k_v1 < 0 || k_i1 < k_v1) { // read numeric after value: - local k_val1 = s.indexOf("\"value\":", k_i1) + 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 } } // second arg after first - local k_i2 = s.indexOf("\"type\":\"Int\"", k_i1 + 1) - local k_v2a = s.indexOf("\"type\":\"Var\"", k_i1 + 1) + 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 = s.indexOf("\"value\":", k_i2) + 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 } } } else if k_v2a >= 0 { // second arg is Var: resolve Local Int value - local kn = s.indexOf("\"name\":\"", k_v2a) + local kn = JsonFragBox.index_of_from(s, "\"name\":\"", k_v2a) if kn >= 0 { local name2 = JsonFragBox.read_string_after(s, kn) - // scan backwards for Local name2 Int - local pos = 0; local last = -1 - loop(true) { - local kL = s.indexOf("\"type\":\"Local\"", pos) - if kL < 0 || kL >= k_m { break } - local nm = null - { - local kn2 = s.indexOf("\"name\":\"", kL) - if kn2 >= 0 { - local iii = kn2 + 8; local nnn = s.length(); local jjj = iii - loop(jjj < nnn) { if s.substring(jjj,jjj+1) == '"' { break } jjj = jjj + 1 } - nm = s.substring(iii, jjj) - } - } - if nm != null && nm == name2 { last = kL } - pos = kL + 1 - } - if last >= 0 { - local ki = s.indexOf("\"type\":\"Int\"", last) - if ki >= 0 && ki < k_m { - local kv = s.indexOf("\"value\":", ki) - if kv >= 0 { local v = JsonFragBox.read_int_after(s, kv + 8); if v != null { b0.push(MirSchemaBox.inst_const(next_id, v)) args_ids.push(next_id) next_id = next_id + 1 } } - } - } + 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 } } } } else if k_v1 >= 0 && (k_i1 < 0 || k_v1 < k_i1) { // first arg is Var: resolve Local value (Int/Bool/Float/String) - local kn = s.indexOf("\"name\":\"", k_v1) + local kn = JsonFragBox.index_of_from(s, "\"name\":\"", k_v1) if kn >= 0 { local namev = JsonFragBox.read_string_after(s, kn) - // find last Local namev Int before method - local pos2 = 0; local last2 = -1 - loop(true) { - local kL2 = s.indexOf("\"type\":\"Local\"", pos2) - if kL2 < 0 || kL2 >= k_m { break } - local nm2 = null - { - local knm = s.indexOf("\"name\":\"", kL2) - if knm >= 0 { - local iii2 = knm + 8; local nnn2 = s.length(); local jjj2 = iii2 - loop(jjj2 < nnn2) { if s.substring(jjj2,jjj2+1) == '"' { break } jjj2 = jjj2 + 1 } - nm2 = s.substring(iii2, jjj2) - } - } - if nm2 != null && nm2 == namev { last2 = kL2 } - pos2 = kL2 + 1 + // Prefer exact-name Local lookups via PatternUtilBox + // 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 last2 >= 0 { - // Int - local ki3 = s.indexOf("\"type\":\"Int\"", last2) - if ki3 >= 0 && ki3 < k_m { local kv3 = s.indexOf("\"value\":", ki3); if kv3 >= 0 { local v = JsonFragBox.read_int_after(s, kv3 + 8); if v != null { b0.push(MirSchemaBox.inst_const(next_id, v)) args_ids.push(next_id) next_id = next_id + 1 } } } - // Bool - local kb3 = s.indexOf("\"type\":\"Bool\"", last2) - if kb3 >= 0 && kb3 < k_m { local kvb = s.indexOf("\"value\":", kb3); if kvb >= 0 { local vb = JsonFragBox.read_bool_after(s, kvb + 8); if vb != null { b0.push(MirSchemaBox.inst_const(next_id, vb)) args_ids.push(next_id) next_id = next_id + 1 } } } - // Float - local kf3 = s.indexOf("\"type\":\"Float\"", last2) - if kf3 >= 0 && kf3 < k_m { local kvf = s.indexOf("\"value\":", kf3); if kvf >= 0 { local fv = JsonFragBox.read_float_after(s, kvf + 8); if fv != null { b0.push(MirSchemaBox.inst_const_f64(next_id, fv)) args_ids.push(next_id) next_id = next_id + 1 } } } - // String - local ks3 = s.indexOf("\"type\":\"String\"", last2) - if ks3 >= 0 && ks3 < k_m { local kvs = s.indexOf("\"value\":\"", ks3); if kvs >= 0 { local sv = JsonFragBox.read_string_after(s, kvs + 8); if sv != null { b0.push(MirSchemaBox.inst_const_str(next_id, sv)) args_ids.push(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 } + } + { + 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 } + } + { + 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 } } } } diff --git a/lang/src/mir/builder/internal/lower_return_string_box.hako b/lang/src/mir/builder/internal/lower_return_string_box.hako index 3d392579..08562e51 100644 --- a/lang/src/mir/builder/internal/lower_return_string_box.hako +++ b/lang/src/mir/builder/internal/lower_return_string_box.hako @@ -6,11 +6,11 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox static box LowerReturnStringBox { try_lower(program_json) { local s = "" + program_json - local k_ret = s.indexOf("\"type\":\"Return\"") + local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0) if k_ret < 0 { return null } - local k_str = s.indexOf("\"type\":\"String\"", k_ret) + local k_str = JsonFragBox.index_of_from(s, "\"type\":\"String\"", k_ret) if k_str < 0 { return null } - local k_val = s.indexOf("\"value\":", k_str) + 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 } diff --git a/lang/src/mir/builder/internal/lower_return_var_local_box.hako b/lang/src/mir/builder/internal/lower_return_var_local_box.hako index 93ea4741..fb8051d1 100644 --- a/lang/src/mir/builder/internal/lower_return_var_local_box.hako +++ b/lang/src/mir/builder/internal/lower_return_var_local_box.hako @@ -7,25 +7,25 @@ static box LowerReturnVarLocalBox { try_lower(program_json) { local s = "" + program_json // Find Local with name:"x" and expr Int value - local k_loc = s.indexOf("\"type\":\"Local\"") + local k_loc = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", 0) if k_loc < 0 { return null } // Extract name - local k_name = s.indexOf("\"name\":", k_loc); if k_name < 0 { return null } + local k_name = JsonFragBox.index_of_from(s, "\"name\":", k_loc); if k_name < 0 { return null } local name = JsonFragBox.read_string_after(s, k_name + 5) if name == null || name == "" { return null } // Ensure expr Int after this Local - local k_int = s.indexOf("\"type\":\"Int\"", k_loc) + local k_int = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_loc) if k_int < 0 { return null } - local kv = s.indexOf("\"value\":", k_int); if kv < 0 { return null } + 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 } // Following Return Var(name) - local k_ret = s.indexOf("\"type\":\"Return\"", k_loc) + local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", k_loc) if k_ret < 0 { return null } // Verify Var(name) - local k_var = s.indexOf("\"type\":\"Var\"", k_ret) + local k_var = JsonFragBox.index_of_from(s, "\"type\":\"Var\"", k_ret) if k_var < 0 { return null } - local k_vn = s.indexOf("\"name\":", k_var); if k_vn < 0 { return null } + local k_vn = JsonFragBox.index_of_from(s, "\"name\":", k_var); if k_vn < 0 { return null } local vname = JsonFragBox.read_string_after(s, k_vn + 5) if vname == null || vname != name { return null } diff --git a/lang/src/mir/builder/internal/pattern_util_box.hako b/lang/src/mir/builder/internal/pattern_util_box.hako index b1dfa571..83bacdf2 100644 --- a/lang/src/mir/builder/internal/pattern_util_box.hako +++ b/lang/src/mir/builder/internal/pattern_util_box.hako @@ -5,6 +5,7 @@ using selfhost.shared.common.string_helpers as StringHelpers static box PatternUtilBox { map_cmp(sym) { if sym=="<" {return "Lt"} if sym==">" {return "Gt"} if sym=="<=" {return "Le"} if sym==">=" {return "Ge"} if sym=="==" {return "Eq"} if sym=="!=" {return "Ne"} return null } + map_binop(sym) { if sym=="+" {return "Add"} if sym=="-" {return "Sub"} if sym=="*" {return "Mul"} if sym=="/" {return "Div"} return null } // Normalize (op, swapped, limit) → (cmp, limit') where cmp in {Lt, Le, Gt, Ge} // swapped=0: i ? L, swapped=1: L ? i normalize_cmp_limit(op, swapped, limit_str) { @@ -50,9 +51,9 @@ static box PatternUtilBox { // Bound the search between this Local and the next Local/before_pos local next = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last + 1) if next < 0 || next > before_pos { next = before_pos } - local ki = s.indexOf("\"type\":\"Int\"", last) + local ki = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", last) if ki < 0 || ki >= next { return null } - local kv = s.indexOf("\"value\":", ki) + local kv = JsonFragBox.index_of_from(s, "\"value\":", ki) if kv < 0 || kv >= next { return null } return JsonFragBox.read_int_after(s, kv+8) } @@ -62,14 +63,64 @@ static box PatternUtilBox { 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 kb = s.indexOf("\"type\":\"Bool\"", last) + local kb = JsonFragBox.index_of_from(s, "\"type\":\"Bool\"", last) if kb < 0 || kb >= next { return null } - local kv = s.indexOf("\"value\":", kb) + local kv = JsonFragBox.index_of_from(s, "\"value\":", kb) if kv < 0 || kv >= next { return null } // JSON v0 uses 0/1 for bool values, not true/false literals return JsonFragBox.read_int_after(s, kv+8) } + // Find the last Local(String) with given name before a given position. + // Returns raw string or null when not found. + find_local_string_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(jjbefore_pos{ next=before_pos } + local ts=(""+s).indexOf("\"type\":\"String\"", last) + if ts<0||ts>=next { return null } + local kv=(""+s).indexOf("\"value\":\"", ts) + if kv<0||kv>=next { return null } + return JsonFragBox.read_string_after(s, kv+8) + } + + // Find the last Local(Float) with given name before a given position. + // Returns float string (as scanned) or null when not found. + find_local_float_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(jjbefore_pos{ next=before_pos } + local tf=(""+s).indexOf("\"type\":\"Float\"", last) + if tf<0||tf>=next { return null } + local kv=(""+s).indexOf("\"value\":", tf) + if kv<0||kv>=next { return null } + return JsonFragBox.read_float_after(s, kv+8) + } + // Find the last Local(Int) before a given position (name-agnostic). // Returns string digits or null when not found. find_any_local_int_before(s, before_pos) { diff --git a/src/config/env.rs b/src/config/env.rs index bded5b11..99eedff1 100644 --- a/src/config/env.rs +++ b/src/config/env.rs @@ -33,9 +33,12 @@ impl NyashEnv { // Global current env config (thread-safe) use once_cell::sync::OnceCell; +use std::collections::HashSet; +use std::sync::Mutex; use std::sync::RwLock; static GLOBAL_ENV: OnceCell> = OnceCell::new(); +static WARNED_ALIASES: OnceCell>> = OnceCell::new(); // フェーズM.2: PHI_ON_GATED_WARNED削除(phi-legacy簡略化により不要) pub fn current() -> NyashEnv { @@ -376,11 +379,19 @@ pub fn cli_verbose() -> bool { } pub fn enable_using() -> bool { // Phase 15: デフォルトON(using systemはメイン機能) - // NYASH_ENABLE_USING=0 で明示的に無効化可能 + // NYASH_ENABLE_USING=0 で明示的に無効化可能。HAKO_ENABLE_USING は互換のため受理(警告)。 match std::env::var("NYASH_ENABLE_USING").ok().as_deref() { - Some("0") | Some("false") | Some("off") => false, - _ => true, // デフォルト: ON + Some("0") | Some("false") | Some("off") => return false, + Some(_) => return true, + None => {} } + // Fallback to alias + if let Some(v) = std::env::var("HAKO_ENABLE_USING").ok() { + warn_alias_once("HAKO_ENABLE_USING", "NYASH_ENABLE_USING"); + let lv = v.to_ascii_lowercase(); + return !(lv == "0" || lv == "false" || lv == "off"); + } + true // default ON } // ---- Using profiles (dev|ci|prod) ---- @@ -466,7 +477,14 @@ pub fn ny_compiler_stage3() -> bool { /// When enabled, the Rust parser accepts Stage-3 surface (try/catch/finally, throw). /// Default is OFF to keep Stage-2 stable. pub fn parser_stage3() -> bool { - std::env::var("NYASH_PARSER_STAGE3").ok().as_deref() == Some("1") + if std::env::var("NYASH_PARSER_STAGE3").ok().as_deref() == Some("1") { + return true; + } + if std::env::var("HAKO_PARSER_STAGE3").ok().as_deref() == Some("1") { + warn_alias_once("HAKO_PARSER_STAGE3", "NYASH_PARSER_STAGE3"); + return true; + } + false } /// Parser gate for Block‑Postfix Catch acceptance @@ -578,3 +596,72 @@ pub fn oob_strict_fail() -> bool { .or_else(|| env_flag("NYASH_OOB_STRICT_FAIL")) .unwrap_or(false) } + +/// Primary verification route: return true when Hakorune VM is requested as primary. +/// Accepts HAKO_VERIFY_PRIMARY=hakovm (preferred) or legacy HAKO_ROUTE_HAKOVM=1 (deprecated, warns). +pub fn verify_primary_is_hakovm() -> bool { + if std::env::var("HAKO_VERIFY_PRIMARY").ok().as_deref() == Some("hakovm") { + return true; + } + if env_bool("HAKO_ROUTE_HAKOVM") { + warn_alias_once("HAKO_ROUTE_HAKOVM", "HAKO_VERIFY_PRIMARY=hakovm"); + return true; + } + false +} + +fn warn_alias_once(alias: &str, primary: &str) { + let set = WARNED_ALIASES.get_or_init(|| Mutex::new(HashSet::new())); + if let Ok(mut s) = set.lock() { + if !s.contains(alias) { + eprintln!("[deprecate/env] '{}' is deprecated; use '{}'", alias, primary); + s.insert(alias.to_string()); + } + } +} + +// ---- ENV consolidation helpers (Phase 21.10/22.1) ---- +/// LLVM opt level (primary: NYASH_LLVM_OPT_LEVEL; alias: HAKO_LLVM_OPT_LEVEL) +/// Returns string level (e.g., "0", "1", ...). Default: "0" when unset. +pub fn llvm_opt_level() -> String { + if let Some(v) = std::env::var("NYASH_LLVM_OPT_LEVEL").ok() { + return v; + } + if let Some(v) = std::env::var("HAKO_LLVM_OPT_LEVEL").ok() { + warn_alias_once("HAKO_LLVM_OPT_LEVEL", "NYASH_LLVM_OPT_LEVEL"); + return v; + } + "0".to_string() +} + +/// Gate‑C(Core) route request (primary: NYASH_GATE_C_CORE; alias: HAKO_GATE_C_CORE) +pub fn gate_c_core() -> bool { + if env_bool("NYASH_GATE_C_CORE") { return true; } + if env_bool("HAKO_GATE_C_CORE") { + warn_alias_once("HAKO_GATE_C_CORE", "NYASH_GATE_C_CORE"); + return true; + } + false +} + +/// Consolidated toggle for selfhost NY compiler pipeline. +/// Primary: NYASH_USE_NY_COMPILER=0|1. Legacy disables accepted (with warning): +/// NYASH_DISABLE_NY_COMPILER/HAKO_DISABLE_NY_COMPILER (any true value disables). +pub fn use_ny_compiler() -> bool { + // Primary knob takes precedence when explicitly set + if let Some(v) = std::env::var("NYASH_USE_NY_COMPILER").ok() { + let lv = v.trim().to_ascii_lowercase(); + return lv == "1" || lv == "true" || lv == "on"; + } + // Legacy disable aliases — if any is true, treat as disabled and warn + if env_bool("NYASH_DISABLE_NY_COMPILER") { + warn_alias_once("NYASH_DISABLE_NY_COMPILER", "NYASH_USE_NY_COMPILER=0"); + return false; + } + if env_bool("HAKO_DISABLE_NY_COMPILER") { + warn_alias_once("HAKO_DISABLE_NY_COMPILER", "NYASH_USE_NY_COMPILER=0"); + return false; + } + // Default: ON (MVP selfhost path) + true +} diff --git a/src/llvm_py/builders/function_lower.py b/src/llvm_py/builders/function_lower.py index c759f10a..03000486 100644 --- a/src/llvm_py/builders/function_lower.py +++ b/src/llvm_py/builders/function_lower.py @@ -24,8 +24,8 @@ def lower_function(builder, func_data: Dict[str, Any]): # Determine function signature if name == "ny_main": - # Special case: ny_main returns i32 - func_ty = ir.FunctionType(builder.i32, []) + # Special case: ny_main returns i64 to match runtime (nyrt) expectations + func_ty = ir.FunctionType(builder.i64, []) else: # Default: i64(i64, ...) signature; derive arity from '/N' suffix when params missing m = re.search(r"/(\d+)$", name) diff --git a/src/llvm_py/instructions/binop.py b/src/llvm_py/instructions/binop.py index fdc09b05..cdc0c5f2 100644 --- a/src/llvm_py/instructions/binop.py +++ b/src/llvm_py/instructions/binop.py @@ -45,7 +45,23 @@ def lower_binop( lhs_val = ir.Constant(ir.IntType(64), 0) if rhs_val is None: rhs_val = ir.Constant(ir.IntType(64), 0) - + # Normalize operation aliases (textual -> symbolic) + op_raw = op or '' + op_l = op_raw.lower() + alias = { + 'add': '+', 'plus': '+', + 'sub': '-', 'minus': '-', + 'mul': '*', 'times': '*', + 'div': '/', + 'mod': '%', 'rem': '%', + 'band': '&', 'bitand': '&', + 'bor': '|', 'bitor': '|', + 'bxor': '^', 'xor': '^', + 'shl': '<<', + 'shr': '>>', 'ashr': '>>', + } + op = alias.get(op_l, op_raw) + # Relational/equality operators delegate to compare if op in ('==','!=','<','>','<=','>='): # Delegate to compare with resolver/preds context to maintain dominance via localization diff --git a/src/llvm_py/instructions/ret.py b/src/llvm_py/instructions/ret.py index 93f49d3d..52b38ba9 100644 --- a/src/llvm_py/instructions/ret.py +++ b/src/llvm_py/instructions/ret.py @@ -97,9 +97,16 @@ def lower_return( # Pointer type - null ret_val = ir.Constant(return_type, None) - # If still zero-like and we have predecessor snapshots, synthesize a minimal PHI at block head. + # If still zero-like (typed zero) and we have predecessor snapshots, synthesize a minimal PHI at block head. try: - zero_like = isinstance(ret_val, ir.Constant) + zero_like = False + if isinstance(ret_val, ir.Constant): + if isinstance(return_type, ir.IntType): + zero_like = (str(ret_val) == str(ir.Constant(return_type, 0))) + elif isinstance(return_type, ir.DoubleType): + zero_like = (str(ret_val) == str(ir.Constant(return_type, 0.0))) + elif isinstance(return_type, ir.PointerType): + zero_like = (str(ret_val) == str(ir.Constant(return_type, None))) if zero_like and preds is not None and block_end_values is not None and bb_map is not None and isinstance(value_id, int): # Derive current block id from name like 'bb3' cur_bid = None diff --git a/src/llvm_py/llvm_builder.py b/src/llvm_py/llvm_builder.py index abe2302e..a8b6959a 100644 --- a/src/llvm_py/llvm_builder.py +++ b/src/llvm_py/llvm_builder.py @@ -152,7 +152,8 @@ class NyashLLVMBuilder: else: arity = int(m.group(1)) if m else len(params_list) if name == "ny_main": - fty = ir.FunctionType(self.i32, []) + # Align with runtime expectation: ny_main returns i64 + fty = ir.FunctionType(self.i64, []) else: fty = ir.FunctionType(self.i64, [self.i64] * arity) exists = False diff --git a/src/main.rs b/src/main.rs index 4fb9fe75..f4006b0e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,8 +13,7 @@ fn main() { // If NYASH_VERIFY_JSON is present and route is requested, execute and exit. // This avoids plugin host/registry initialization and keeps output minimal. let has_json = std::env::var("NYASH_VERIFY_JSON").is_ok(); - let route = nyash_rust::config::env::env_bool("HAKO_ROUTE_HAKOVM") - || std::env::var("HAKO_VERIFY_PRIMARY").ok().as_deref() == Some("hakovm"); + let route = nyash_rust::config::env::verify_primary_is_hakovm(); // Force flag may allow hv1-inline without route let force_hv1_flag = nyash_rust::config::env::env_bool("HAKO_VERIFY_V1_FORCE_HAKOVM"); if has_json && (route || force_hv1_flag) { diff --git a/src/runner/dispatch.rs b/src/runner/dispatch.rs index 3b6e94ff..5992d0e0 100644 --- a/src/runner/dispatch.rs +++ b/src/runner/dispatch.rs @@ -12,30 +12,9 @@ pub(crate) fn execute_file_with_backend(runner: &NyashRunner, filename: &str) { // Note: hv1 direct route is now handled at main.rs entry point (before NyashRunner creation). // This function is only called after plugins and runner initialization have already occurred. - // Selfhost pipeline (Ny -> JSON v0) - // Default: ON. Backward‑compat envs: - // - NYASH_USE_NY_COMPILER={1|true|on} to force ON - // - NYASH_USE_NY_COMPILER={0|false|off} or NYASH_DISABLE_NY_COMPILER/HAKO_DISABLE_NY_COMPILER to disable - let mut use_selfhost = true; - if let Ok(v) = std::env::var("NYASH_USE_NY_COMPILER") { - let lv = v.trim().to_ascii_lowercase(); - use_selfhost = matches!(lv.as_str(), "1" | "true" | "on"); - } - let disabled = std::env::var("NYASH_DISABLE_NY_COMPILER") - .ok() - .map(|v| { - let lv = v.trim().to_ascii_lowercase(); - matches!(lv.as_str(), "1" | "true" | "on") - }) - .unwrap_or(false) - || std::env::var("HAKO_DISABLE_NY_COMPILER") - .ok() - .map(|v| { - let lv = v.trim().to_ascii_lowercase(); - matches!(lv.as_str(), "1" | "true" | "on") - }) - .unwrap_or(false); - if use_selfhost && !disabled { + // Selfhost pipeline (Ny -> JSON v0) — consolidated env toggle + // Primary: NYASH_USE_NY_COMPILER=0|1; legacy disables accepted with deprecation warning + if crate::config::env::use_ny_compiler() { if runner.try_run_selfhost_pipeline(filename) { return; } else { diff --git a/tools/native_llvm_builder.py b/tools/native_llvm_builder.py new file mode 100644 index 00000000..63daec7f --- /dev/null +++ b/tools/native_llvm_builder.py @@ -0,0 +1,241 @@ +#!/usr/bin/env python3 +""" +Native LLVM Builder (bootstrap) + +Goal: minimal Python-only emitter that generates LLVM IR text from a tiny +subset of Nyash MIR JSON and compiles it to an object via `llc`. + +Supported (MVP): +- schema_version v1 or tolerant shapes +- Single function: ny_main(): i64 +- Instructions: const(i64), binop(add/sub/mul/div/mod/&/|/^/<< >>), compare(==) +- ret(value) + +Usage: + python3 tools/native_llvm_builder.py --in in.json --emit obj --out out.o + +Notes: +- No external Python packages required. Assumes `llc` is in PATH. +""" + +import argparse +import json +import os +import subprocess +import sys +from pathlib import Path + + +def _normalize_canary(v: dict) -> dict: + # Coerce schema_version + sv = v.get("schema_version") + if isinstance(sv, int) and sv == 1: + v["schema_version"] = "1.0" + if isinstance(sv, str) and sv == "1": + v["schema_version"] = "1.0" + # Normalize blocks.inst -> instructions + funs = v.get("functions") + if isinstance(funs, list): + for f in funs: + blks = f.get("blocks") + if isinstance(blks, list): + for b in blks: + if "inst" in b and "instructions" not in b: + b["instructions"] = b.pop("inst") + ins = b.get("instructions") + if isinstance(ins, list): + for insn in ins: + if insn.get("op") == "const": + if "value" in insn and isinstance(insn["value"], dict) and "type" in insn["value"]: + pass + else: + ty = insn.pop("ty", "i64") + val = insn.pop("value", 0) + insn["value"] = {"type": ty, "value": val} + return v + + +def build_ir(ny_json: dict) -> str: + ny = _normalize_canary(ny_json) + funs = ny.get("functions", []) + fn = None + for f in funs: + if f.get("name") == "ny_main": + fn = f + break + if fn is None: + raise ValueError("ny_main not found") + blocks = fn.get("blocks", []) + if not blocks: + # trivial + return ( + "; ModuleID = \"nyash_native\"\n" + "define i64 @ny_main(){\n ret i64 0\n}\n" + ) + + # IR pieces + lines = [] + # Keep IR minimal; let llc choose target triple/datalayout + lines.append("; ModuleID = \"nyash_native\"") + lines.append("") + lines.append("define i64 @ny_main(){") + + # Simple vmap; const map holds immediate ints; ssa map holds emitted names + const_map = {} + ssa_map = {} + is_i1 = set() + + def val_of(vid): + if vid in ssa_map: + return f"%{ssa_map[vid]}", (vid in is_i1) + if vid in const_map: + return f"i64 {const_map[vid]}", False + # default zero + return "i64 0", False + + tmp_idx = 0 + def fresh(name): + nonlocal tmp_idx + tmp_idx += 1 + return f"{name}_{tmp_idx}" + + # Emit each block with an explicit label: bb: + for b in blocks: + bid = b.get("id") + lines.append(f"bb{bid}:") + ins = b.get("instructions", []) + for insn in ins: + op = insn.get("op") + if op == "const": + dst = insn.get("dst") + v = insn.get("value", {}) + ty = v.get("type", insn.get("ty", "i64")) + val = v.get("value", 0) + if ty != "i64": + val = 0 + const_map[dst] = int(val) + elif op == "binop": + dst = insn.get("dst") + opx = (insn.get("operation") or '').lower() + aliases = { + 'add': '+', 'plus': '+', 'sub': '-', 'minus': '-', 'mul': '*', 'times': '*', + 'div': '/', 'mod': '%', 'rem': '%', 'band': '&', 'bitand': '&', 'bor': '|', 'bitor': '|', + 'bxor': '^', 'xor': '^', 'shl': '<<', 'shr': '>>', 'ashr': '>>' + } + sym = aliases.get(opx, opx) + lhs = insn.get("lhs"); rhs = insn.get("rhs") + lv, _ = val_of(lhs); rv, _ = val_of(rhs) + name = fresh("bin") + if sym == '+': + lines.append(f" %{name} = add i64 {lv.split()[-1]}, {rv.split()[-1]}") + elif sym == '-': + lines.append(f" %{name} = sub i64 {lv.split()[-1]}, {rv.split()[-1]}") + elif sym == '*': + lines.append(f" %{name} = mul i64 {lv.split()[-1]}, {rv.split()[-1]}") + elif sym == '/': + lines.append(f" %{name} = sdiv i64 {lv.split()[-1]}, {rv.split()[-1]}") + elif sym == '%': + lines.append(f" %{name} = srem i64 {lv.split()[-1]}, {rv.split()[-1]}") + elif sym == '&': + lines.append(f" %{name} = and i64 {lv.split()[-1]}, {rv.split()[-1]}") + elif sym == '|': + lines.append(f" %{name} = or i64 {lv.split()[-1]}, {rv.split()[-1]}") + elif sym == '^': + lines.append(f" %{name} = xor i64 {lv.split()[-1]}, {rv.split()[-1]}") + elif sym == '<<': + lines.append(f" %{name} = shl i64 {lv.split()[-1]}, {rv.split()[-1]}") + elif sym == '>>': + lines.append(f" %{name} = ashr i64 {lv.split()[-1]}, {rv.split()[-1]}") + else: + lines.append(f" %{name} = add i64 0, 0") + ssa_map[dst] = name + elif op == "compare": + dst = insn.get("dst") + opx = insn.get("operation") or insn.get("cmp") or '==' + lhs = insn.get("lhs"); rhs = insn.get("rhs") + lv, _ = val_of(lhs); rv, _ = val_of(rhs) + name = fresh("cmp") + # Support eq/lt minimal + if opx in ('==', 'Eq'): pred = 'eq' + elif opx in ('<', 'Lt'): pred = 'slt' + else: pred = 'ne' + lines.append(f" %{name} = icmp {pred} i64 {lv.split()[-1]}, {rv.split()[-1]}") + ssa_map[dst] = name + is_i1.add(dst) + elif op == "branch": + # Conditional branch: {cond, then, else} + cond = insn.get("cond") + then_id = insn.get("then") + else_id = insn.get("else") + cv, ci1 = val_of(cond) + if ci1: + cond_name = cv if cv.startswith('%') else f"%{cv}" + lines.append(f" br i1 {cond_name}, label %bb{then_id}, label %bb{else_id}") + else: + # Build i1 from i64 via icmp ne 0 + name = fresh("cnd") + lines.append(f" %{name} = icmp ne i64 {cv.split()[-1]}, 0") + lines.append(f" br i1 %{name}, label %bb{then_id}, label %bb{else_id}") + elif op == "jump": + target = insn.get("target") + lines.append(f" br label %bb{target}") + elif op == "ret": + vid = insn.get("value") + if vid in is_i1: + vname = ssa_map.get(vid) + z = fresh("zext") + lines.append(f" %{z} = zext i1 %{vname} to i64") + lines.append(f" ret i64 %{z}") + elif vid in ssa_map: + lines.append(f" ret i64 %{ssa_map[vid]}") + elif vid in const_map: + lines.append(f" ret i64 {const_map[vid]}") + else: + lines.append(" ret i64 0") + lines.append("}") + return "\n".join(lines) + "\n" + + +def compile_ir_to_obj(ir_text: str, out_obj: Path) -> None: + tmp = Path("/tmp/native_ir_{}.ll".format(os.getpid())) + tmp.write_text(ir_text) + try: + subprocess.check_call(["llc", "-filetype=obj", "-o", str(out_obj), str(tmp)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + finally: + try: + tmp.unlink() + except Exception: + pass + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--in", dest="infile", required=True) + ap.add_argument("--emit", dest="emit", default="obj") + ap.add_argument("--out", dest="out", required=True) + args = ap.parse_args() + + with open(args.infile, 'r') as f: + ny = json.load(f) + + ir = build_ir(ny) + if os.environ.get('NYASH_LLVM_NATIVE_TRACE') in ('1','true','on','YES','yes','True'): + print(ir, file=sys.stderr) + if args.emit == 'll': + Path(args.out).write_text(ir) + print(f"[native] ll written: {args.out}") + return + if args.emit == 'obj': + compile_ir_to_obj(ir, Path(args.out)) + print(f"[native] obj written: {args.out}") + return + print("error: unsupported emit kind", file=sys.stderr) + sys.exit(2) + + +if __name__ == "__main__": + try: + main() + except Exception as e: + print(f"[native] error: {e}", file=sys.stderr) + sys.exit(1) diff --git a/tools/ny_mir_builder.sh b/tools/ny_mir_builder.sh index 36e97c7e..e0d25dc0 100644 --- a/tools/ny_mir_builder.sh +++ b/tools/ny_mir_builder.sh @@ -24,7 +24,17 @@ TARGET="" NYRT_DIR="" VERIFY=0 QUIET=0 -BACKEND="${NYASH_LLVM_BACKEND:-llvmlite}" # llvmlite | crate | native (reserved) +# Backend selection (21.11): default to 'crate' when ny-llvmc is available, otherwise fallback to llvmlite. +# Explicit env NYASH_LLVM_BACKEND overrides this auto-detection. +if [[ -n "${NYASH_LLVM_BACKEND:-}" ]]; then + BACKEND="${NYASH_LLVM_BACKEND}" +else + if [[ -x "./target/release/ny-llvmc" ]]; then + BACKEND="crate" + else + BACKEND="llvmlite" + fi +fi while [[ $# -gt 0 ]]; do case "$1" in @@ -51,9 +61,12 @@ if [[ -z "$OUT" ]]; then esac fi -if ! command -v llvm-config-18 >/dev/null 2>&1; then - echo "error: llvm-config-18 not found (install LLVM 18 dev)" >&2 - exit 3 +# Require LLVM18 only for llvmlite backend +if [[ "${NYASH_LLVM_BACKEND:-$BACKEND}" == "llvmlite" ]]; then + if ! command -v llvm-config-18 >/dev/null 2>&1; then + echo "error: llvm-config-18 not found (install LLVM 18 dev)" >&2 + exit 3 + fi fi # Build nyash + NyRT as needed(skip allowed) @@ -126,6 +139,15 @@ case "$EMIT" in rm -f "$OUT" "$BIN_NYLLVMC" --in "$IN_FILE" --emit obj --out "$OUT" >/dev/null 2>&1 || { echo "error: ny-llvmc failed" >&2; exit 4; } ;; + native) + if ! command -v llc >/dev/null 2>&1; then + echo "error: llc not found (install LLVM tools)" >&2; exit 4 + fi + rm -f "$OUT" + if ! python3 "$PWD/tools/native_llvm_builder.py" --in "$IN_FILE" --emit obj --out "$OUT" >/dev/null 2>&1; then + echo "error: native builder failed" >&2; exit 4 + fi + ;; llvmlite|*) # Directly use llvmlite harness with MIR v1 JSON input rm -f "$OUT" @@ -153,6 +175,22 @@ case "$EMIT" in echo "error: ny-llvmc failed to link exe" >&2; exit 4 fi ;; + native) + if ! command -v llc >/dev/null 2>&1; then + echo "error: llc not found (install LLVM tools)" >&2; exit 4 + fi + if ! python3 "$PWD/tools/native_llvm_builder.py" --in "$IN_FILE" --emit obj --out "$OBJ" >/dev/null 2>&1; then + echo "error: native builder failed to produce object $OBJ" >&2; exit 4 + fi + if [[ ! -f "$OBJ" ]]; then echo "error: failed to produce object $OBJ" >&2; exit 4; fi + # Link with NyRT (same as llvmlite branch) + NYRT_BASE=${NYRT_DIR:-"$PWD/crates/nyash_kernel"} + cc "$OBJ" \ + -L target/release \ + -L "$NYRT_BASE/target/release" \ + -Wl,--whole-archive -lnyash_kernel -Wl,--no-whole-archive \ + -lpthread -ldl -lm -o "$OUT" + ;; llvmlite|*) if ! python3 "$PWD/tools/llvmlite_harness.py" --in "$IN_FILE" --out "$OBJ" >/dev/null 2>&1; then echo "error: harness failed to produce object $OBJ" >&2; exit 4 diff --git a/tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_internal_if_compare_varint_negative_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_internal_if_compare_varint_negative_canary_vm.sh new file mode 100644 index 00000000..d136dedb --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_internal_if_compare_varint_negative_canary_vm.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# If(Compare Var/Int) with negative numbers → compare+branch+ret (structure check) +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_hako="/tmp/mirbuilder_if_varint_neg_$$.hako" +cat > "$tmp_hako" <<'HAKO' +include "lang/src/mir/builder/MirBuilderBox.hako" +static box Main { method main(args) { + // Local a=-5; if (a < -3) return 1; else return 0; + local j = "{\"version\":0,\"kind\":\"Program\",\"body\":[" + + "{\"type\":\"Local\",\"name\":\"a\",\"expr\":{\"type\":\"Int\",\"value\":-5}}," + + "{\"type\":\"If\",\"cond\":{\"type\":\"Compare\",\"op\":\"<\",\"lhs\":{\"type\":\"Var\",\"name\":\"a\"},\"rhs\":{\"type\":\"Int\",\"value\":-3}},\"then\":[{\"type\":\"Return\",\"expr\":{\"type\":\"Int\",\"value\":1}}],\"else\":[{\"type\":\"Return\",\"expr\":{\"type\":\"Int\",\"value\":0}}]}]}"; + local out = MirBuilderBox.emit_from_program_json_v0(j, null); + if out == null { return 0 } + local s = "" + out + if s.indexOf("\"op\":\"compare\"") >= 0 && s.indexOf("\"op\":\"branch\"") >= 0 { return 1 } + return 0 +} } +HAKO + +set +e +out="$(HAKO_MIR_BUILDER_INTERNAL=1 "$NYASH_BIN" --backend vm "$tmp_hako" 2>&1)"; rc=$? +set -e +rm -f "$tmp_hako" || true + +if [ "$rc" -eq 1 ]; then echo "[PASS] mirbuilder_internal_if_compare_varint_negative_canary_vm"; exit 0; fi +echo "[FAIL] mirbuilder_internal_if_compare_varint_negative_canary_vm (rc=$rc)" >&2; exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_internal_return_binop_varint_negative_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_internal_return_binop_varint_negative_canary_vm.sh new file mode 100644 index 00000000..5617060d --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_internal_return_binop_varint_negative_canary_vm.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# Return(Binary Var/Int) with negative constants → const+const+binop+ret (structure) +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_hako="/tmp/mirbuilder_return_binop_varint_neg_$$.hako" +cat > "$tmp_hako" <<'HAKO' +include "lang/src/mir/builder/MirBuilderBox.hako" +static box Main { method main(args) { + // Local x=-2; return x + -3; + local j = "{\"version\":0,\"kind\":\"Program\",\"body\":[{\"type\":\"Local\",\"name\":\"x\",\"expr\":{\"type\":\"Int\",\"value\":-2}},{\"type\":\"Return\",\"expr\":{\"type\":\"Binary\",\"op\":\"+\",\"lhs\":{\"type\":\"Var\",\"name\":\"x\"},\"rhs\":{\"type\":\"Int\",\"value\":-3}}}]}"; + local out = MirBuilderBox.emit_from_program_json_v0(j, null); + if out == null { return 0 } + local s = "" + out + if s.indexOf("\"op\":\"binop\"") >= 0 && s.indexOf("\"op_kind\":\"Add\"") >= 0 { return 1 } + return 0 +} } +HAKO + +set +e +out="$(HAKO_MIR_BUILDER_INTERNAL=1 "$NYASH_BIN" --backend vm "$tmp_hako" 2>&1)"; rc=$? +set -e +rm -f "$tmp_hako" || true + +if [ "$rc" -eq 1 ]; then echo "[PASS] mirbuilder_internal_return_binop_varint_negative_canary_vm"; exit 0; fi +echo "[FAIL] mirbuilder_internal_return_binop_varint_negative_canary_vm (rc=$rc)" >&2; exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/run_all.sh b/tools/smokes/v2/profiles/quick/core/phase2100/run_all.sh index 175deb9d..2502c066 100644 --- a/tools/smokes/v2/profiles/quick/core/phase2100/run_all.sh +++ b/tools/smokes/v2/profiles/quick/core/phase2100/run_all.sh @@ -64,4 +64,34 @@ if [[ "${SMOKES_ENABLE_SELFHOST:-0}" == "1" ]]; then fi fi +# Crate backend (ny-llvmc) — run a tiny representative set always when available + echo "[phase2100] S3 (crate ny-llvmc) reps..." +( + set -e + # Prebuild crate tools quickly (best-effort) + (cd "$ROOT/crates/nyash-llvm-compiler" && timeout 180 cargo build --release -j 24 >/dev/null 2>&1) || true + (cd "$ROOT/crates/nyash_kernel" && timeout 180 cargo build --release -j 24 >/dev/null 2>&1) || true + # Probe ny-llvmc availability by compiling a minimal ret0 ny_main + BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" + if [[ -x "$BIN_NYLLVMC" ]]; then + tmpj="/tmp/ny_crate_probe_$$.json"; echo '{"schema_version":1,"functions":[{"name":"ny_main","blocks":[{"id":0,"inst":[{"op":"const","dst":1,"ty":"i64","value":0},{"op":"ret","value":1}]}]}]}' > "$tmpj" + tmpo="/tmp/ny_crate_probe_$$.o" + if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$tmpj" --out "$tmpo" >/dev/null 2>&1; then + rm -f "$tmpo" "$tmpj" || true + # Run representative crate EXE canaries (fast) + bash "$ROOT/tools/smokes/v2/run.sh" --profile quick --filter 'phase2100/s3_backend_selector_crate_exe_return42_canary_vm.sh' + bash "$ROOT/tools/smokes/v2/run.sh" --profile quick --filter 'phase2100/s3_backend_selector_crate_exe_compare_eq_true_canary_vm.sh' + bash "$ROOT/tools/smokes/v2/run.sh" --profile quick --filter 'phase2100/s3_backend_selector_crate_exe_binop_return_canary_vm.sh' + else + rm -f "$tmpo" "$tmpj" || true + echo "[phase2100] SKIP crate reps (ny-llvmc probe failed)" >&2 + fi + else + echo "[phase2100] SKIP crate reps (ny-llvmc not built)" >&2 + fi +) || echo "[phase2100] crate reps encountered a non-fatal issue; continuing" + +# SSOT relative inference — unique case (always-on, quick) +bash "$ROOT/tools/smokes/v2/run.sh" --profile quick --filter 'phase2211/ssot_relative_unique_canary_vm.sh' + echo "[phase2100] Done." diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_binop_return_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_binop_return_canary_vm.sh new file mode 100644 index 00000000..ea24651f --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_binop_return_canary_vm.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" + +# Prebuild required tools/libraries +(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true +(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true + +# Minimal MIR v1 JSON that computes 40+2 then returns 42. +JSON='{ + "schema_version": 1, + "functions": [ + {"name":"ny_main","blocks":[ + {"id":0,"inst":[ + {"op":"const","dst":1,"ty":"i64","value":40}, + {"op":"const","dst":2,"ty":"i64","value":2}, + {"op":"binop","operation":"add","lhs":1,"rhs":2,"dst":3}, + {"op":"ret","value":3} + ]} + ]} + ] +}' + +APP="/tmp/ny_crate_backend_exe_binop_$$" +TMP_JSON="/tmp/ny_crate_backend_exe_binop_$$.json" +echo "$JSON" > "$TMP_JSON" + +if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then + if [[ -x "$APP" ]]; then + set +e + "$APP" >/dev/null 2>&1; rc=$? + set -e + if [ "$rc" -eq 42 ]; then + echo "[PASS] s3_backend_selector_crate_exe_binop_return_canary_vm" + rm -f "$APP" "$TMP_JSON" 2>/dev/null || true + exit 0 + fi + fi +fi +echo "[FAIL] s3_backend_selector_crate_exe_binop_return_canary_vm" >&2 +rm -f "$APP" "$TMP_JSON" 2>/dev/null || true +exit 1 diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_bitwise_and_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_bitwise_and_canary_vm.sh new file mode 100644 index 00000000..382ec262 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_bitwise_and_canary_vm.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" + +(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true +(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true + +JSON='{ + "schema_version": 1, + "functions": [ + {"name":"ny_main","blocks":[ + {"id":0,"inst":[ + {"op":"const","dst":1,"ty":"i64","value":5}, + {"op":"const","dst":2,"ty":"i64","value":3}, + {"op":"binop","operation":"&","lhs":1,"rhs":2,"dst":3}, + {"op":"ret","value":3} + ]} + ]} + ] +}' + +APP="/tmp/ny_crate_backend_exe_and_$$" +TMP_JSON="/tmp/ny_crate_backend_exe_and_$$.json" +echo "$JSON" > "$TMP_JSON" + +if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then + if [[ -x "$APP" ]]; then + set +e + "$APP" >/dev/null 2>&1; rc=$? + set -e + if [ "$rc" -eq 1 ]; then + echo "[PASS] s3_backend_selector_crate_exe_bitwise_and_canary_vm" + rm -f "$APP" "$TMP_JSON" 2>/dev/null || true + exit 0 + fi + fi +fi +echo "[FAIL] s3_backend_selector_crate_exe_bitwise_and_canary_vm" >&2 +rm -f "$APP" "$TMP_JSON" 2>/dev/null || true +exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_eq_true_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_eq_true_canary_vm.sh new file mode 100644 index 00000000..dd3b3b60 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_eq_true_canary_vm.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" + +(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true +(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true + +JSON='{ + "schema_version": 1, + "functions": [ + {"name":"ny_main","blocks":[ + {"id":0,"inst":[ + {"op":"const","dst":1,"ty":"i64","value":7}, + {"op":"const","dst":2,"ty":"i64","value":7}, + {"op":"compare","operation":"==","lhs":1,"rhs":2,"dst":3}, + {"op":"ret","value":3} + ]} + ]} + ] +}' + +APP="/tmp/ny_crate_backend_exe_cmp_eq_$$" +TMP_JSON="/tmp/ny_crate_backend_exe_cmp_eq_$$.json" +echo "$JSON" > "$TMP_JSON" + +if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then + if [[ -x "$APP" ]]; then + set +e + "$APP" >/dev/null 2>&1; rc=$? + set -e + if [ "$rc" -eq 1 ]; then + echo "[PASS] s3_backend_selector_crate_exe_compare_eq_true_canary_vm" + rm -f "$APP" "$TMP_JSON" 2>/dev/null || true + exit 0 + fi + fi +fi +echo "[FAIL] s3_backend_selector_crate_exe_compare_eq_true_canary_vm" >&2 +rm -f "$APP" "$TMP_JSON" 2>/dev/null || true +exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_ge_boundary_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_ge_boundary_canary_vm.sh new file mode 100644 index 00000000..be6b4608 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_ge_boundary_canary_vm.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" + +(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true +(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true + +JSON='{ + "schema_version": 1, + "functions": [ + {"name":"ny_main","blocks":[ + {"id":0,"inst":[ + {"op":"const","dst":1,"ty":"i64","value":0}, + {"op":"const","dst":2,"ty":"i64","value":-1}, + {"op":"compare","operation":">=","lhs":1,"rhs":2,"dst":3}, + {"op":"ret","value":3} + ]} + ]} + ] +}' + +APP="/tmp/ny_crate_backend_exe_cmp_ge_b_$$" +TMP_JSON="/tmp/ny_crate_backend_exe_cmp_ge_b_$$.json" +echo "$JSON" > "$TMP_JSON" + +if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then + if [[ -x "$APP" ]]; then + set +e + "$APP" >/dev/null 2>&1; rc=$? + set -e + if [ "$rc" -eq 1 ]; then + echo "[PASS] s3_backend_selector_crate_exe_compare_ge_boundary_canary_vm" + rm -f "$APP" "$TMP_JSON" 2>/dev/null || true + exit 0 + fi + fi +fi +echo "[FAIL] s3_backend_selector_crate_exe_compare_ge_boundary_canary_vm" >&2 +rm -f "$APP" "$TMP_JSON" 2>/dev/null || true +exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_le_boundary_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_le_boundary_canary_vm.sh new file mode 100644 index 00000000..0c3e51f0 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_le_boundary_canary_vm.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" + +(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true +(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true + +JSON='{ + "schema_version": 1, + "functions": [ + {"name":"ny_main","blocks":[ + {"id":0,"inst":[ + {"op":"const","dst":1,"ty":"i64","value":-1}, + {"op":"const","dst":2,"ty":"i64","value":0}, + {"op":"compare","operation":"<=","lhs":1,"rhs":2,"dst":3}, + {"op":"ret","value":3} + ]} + ]} + ] +}' + +APP="/tmp/ny_crate_backend_exe_cmp_le_b_$$" +TMP_JSON="/tmp/ny_crate_backend_exe_cmp_le_b_$$.json" +echo "$JSON" > "$TMP_JSON" + +if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then + if [[ -x "$APP" ]]; then + set +e + "$APP" >/dev/null 2>&1; rc=$? + set -e + if [ "$rc" -eq 1 ]; then + echo "[PASS] s3_backend_selector_crate_exe_compare_le_boundary_canary_vm" + rm -f "$APP" "$TMP_JSON" 2>/dev/null || true + exit 0 + fi + fi +fi +echo "[FAIL] s3_backend_selector_crate_exe_compare_le_boundary_canary_vm" >&2 +rm -f "$APP" "$TMP_JSON" 2>/dev/null || true +exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_lt_neg_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_lt_neg_canary_vm.sh new file mode 100644 index 00000000..05e6a327 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_lt_neg_canary_vm.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" + +(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true +(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true + +JSON='{ + "schema_version": 1, + "functions": [ + {"name":"ny_main","blocks":[ + {"id":0,"inst":[ + {"op":"const","dst":1,"ty":"i64","value":-5}, + {"op":"const","dst":2,"ty":"i64","value":0}, + {"op":"compare","operation":"<","lhs":1,"rhs":2,"dst":3}, + {"op":"ret","value":3} + ]} + ]} + ] +}' + +APP="/tmp/ny_crate_backend_exe_cmp_lt_neg_$$" +TMP_JSON="/tmp/ny_crate_backend_exe_cmp_lt_neg_$$.json" +echo "$JSON" > "$TMP_JSON" + +if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then + if [[ -x "$APP" ]]; then + set +e + "$APP" >/dev/null 2>&1; rc=$? + set -e + if [ "$rc" -eq 1 ]; then + echo "[PASS] s3_backend_selector_crate_exe_compare_lt_neg_canary_vm" + rm -f "$APP" "$TMP_JSON" 2>/dev/null || true + exit 0 + fi + fi +fi +echo "[FAIL] s3_backend_selector_crate_exe_compare_lt_neg_canary_vm" >&2 +rm -f "$APP" "$TMP_JSON" 2>/dev/null || true +exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_ne_true_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_ne_true_canary_vm.sh new file mode 100644 index 00000000..1b1f2c66 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_ne_true_canary_vm.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" + +(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true +(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true + +JSON='{ + "schema_version": 1, + "functions": [ + {"name":"ny_main","blocks":[ + {"id":0,"inst":[ + {"op":"const","dst":1,"ty":"i64","value":7}, + {"op":"const","dst":2,"ty":"i64","value":8}, + {"op":"compare","operation":"!=","lhs":1,"rhs":2,"dst":3}, + {"op":"ret","value":3} + ]} + ]} + ] +}' + +APP="/tmp/ny_crate_backend_exe_cmp_ne_$$" +TMP_JSON="/tmp/ny_crate_backend_exe_cmp_ne_$$.json" +echo "$JSON" > "$TMP_JSON" + +if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then + if [[ -x "$APP" ]]; then + set +e + "$APP" >/dev/null 2>&1; rc=$? + set -e + if [ "$rc" -eq 1 ]; then + echo "[PASS] s3_backend_selector_crate_exe_compare_ne_true_canary_vm" + rm -f "$APP" "$TMP_JSON" 2>/dev/null || true + exit 0 + fi + fi +fi +echo "[FAIL] s3_backend_selector_crate_exe_compare_ne_true_canary_vm" >&2 +rm -f "$APP" "$TMP_JSON" 2>/dev/null || true +exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_div_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_div_canary_vm.sh new file mode 100644 index 00000000..efa840c5 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_div_canary_vm.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" + +(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true +(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true + +JSON='{ + "schema_version": 1, + "functions": [ + {"name":"ny_main","blocks":[ + {"id":0,"inst":[ + {"op":"const","dst":1,"ty":"i64","value":5}, + {"op":"const","dst":2,"ty":"i64","value":2}, + {"op":"binop","operation":"/","lhs":1,"rhs":2,"dst":3}, + {"op":"ret","value":3} + ]} + ]} + ] +}' + +APP="/tmp/ny_crate_backend_exe_div_$$" +TMP_JSON="/tmp/ny_crate_backend_exe_div_$$.json" +echo "$JSON" > "$TMP_JSON" + +if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then + if [[ -x "$APP" ]]; then + set +e + "$APP" >/dev/null 2>&1; rc=$? + set -e + if [ "$rc" -eq 2 ]; then + echo "[PASS] s3_backend_selector_crate_exe_div_canary_vm" + rm -f "$APP" "$TMP_JSON" 2>/dev/null || true + exit 0 + fi + fi +fi +echo "[FAIL] s3_backend_selector_crate_exe_div_canary_vm" >&2 +rm -f "$APP" "$TMP_JSON" 2>/dev/null || true +exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_phi_branch_return42_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_phi_branch_return42_canary_vm.sh new file mode 100644 index 00000000..00a0fcdf --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_phi_branch_return42_canary_vm.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" + +(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true +(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true + +# Branch: if (1 == 1) then return 42 else return 7 → expect rc=42 +JSON='{ + "schema_version": 1, + "functions": [ + {"name":"ny_main","blocks":[ + {"id":0,"inst":[ + {"op":"const","dst":1,"ty":"i64","value":1}, + {"op":"const","dst":2,"ty":"i64","value":1}, + {"op":"compare","operation":"==","lhs":1,"rhs":2,"dst":3}, + {"op":"branch","cond":3,"then":1,"else":2} + ]}, + {"id":1,"inst":[ + {"op":"const","dst":4,"ty":"i64","value":42}, + {"op":"ret","value":4} + ]}, + {"id":2,"inst":[ + {"op":"const","dst":5,"ty":"i64","value":7}, + {"op":"ret","value":5} + ]} + ]} + ] +}' + +APP="/tmp/ny_crate_backend_exe_phi_ret42_$$" +TMP_JSON="/tmp/ny_crate_backend_exe_phi_ret42_$$.json" +echo "$JSON" > "$TMP_JSON" + +if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then + if [[ -x "$APP" ]]; then + set +e + "$APP" >/dev/null 2>&1; rc=$? + set -e + if [ "$rc" -eq 42 ]; then + echo "[PASS] s3_backend_selector_crate_exe_phi_branch_return42_canary_vm" + rm -f "$APP" "$TMP_JSON" 2>/dev/null || true + exit 0 + fi + fi +fi +echo "[FAIL] s3_backend_selector_crate_exe_phi_branch_return42_canary_vm" >&2 +rm -f "$APP" "$TMP_JSON" 2>/dev/null || true +exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_print_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_print_canary_vm.sh index 8d0b7c40..65723b43 100644 --- a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_print_canary_vm.sh +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_print_canary_vm.sh @@ -29,10 +29,10 @@ APP="/tmp/ny_crate_backend_exe_print_$$" TMP_JSON="/tmp/ny_crate_backend_exe_print_$$.json" echo "$JSON" > "$TMP_JSON" -LIBDIR_MIN="$ROOT/crates/nyash_kernel_min_c/target/release" +LIBDIR_MIN="$ROOT/target/release" LIBS="-L $LIBDIR_MIN -lnyash_kernel_min_c" -if "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --libs "$LIBS" --out "$APP" >/dev/null 2>&1; then +if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --libs="$LIBS" --out "$APP" >/dev/null 2>&1; then if [[ -x "$APP" ]]; then set +e out="$($APP 2>/dev/null)"; rc=$? diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_rem_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_rem_canary_vm.sh new file mode 100644 index 00000000..e8f56211 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_rem_canary_vm.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" + +(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true +(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true + +JSON='{ + "schema_version": 1, + "functions": [ + {"name":"ny_main","blocks":[ + {"id":0,"inst":[ + {"op":"const","dst":1,"ty":"i64","value":5}, + {"op":"const","dst":2,"ty":"i64","value":2}, + {"op":"binop","operation":"%","lhs":1,"rhs":2,"dst":3}, + {"op":"ret","value":3} + ]} + ]} + ] +}' + +APP="/tmp/ny_crate_backend_exe_rem_$$" +TMP_JSON="/tmp/ny_crate_backend_exe_rem_$$.json" +echo "$JSON" > "$TMP_JSON" + +if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then + if [[ -x "$APP" ]]; then + set +e + "$APP" >/dev/null 2>&1; rc=$? + set -e + if [ "$rc" -eq 1 ]; then + echo "[PASS] s3_backend_selector_crate_exe_rem_canary_vm" + rm -f "$APP" "$TMP_JSON" 2>/dev/null || true + exit 0 + fi + fi +fi +echo "[FAIL] s3_backend_selector_crate_exe_rem_canary_vm" >&2 +rm -f "$APP" "$TMP_JSON" 2>/dev/null || true +exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_return42_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_return42_canary_vm.sh new file mode 100644 index 00000000..2101a0d5 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_return42_canary_vm.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" + +# Prebuild required tools/libraries +(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true +(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true + +# Minimal MIR v1 JSON that returns 42. +JSON='{ + "schema_version": 1, + "functions": [ + {"name":"ny_main","blocks":[ + {"id":0,"inst":[ + {"op":"const","dst":1,"ty":"i64","value":42}, + {"op":"ret","value":1} + ]} + ]} + ] +}' + +APP="/tmp/ny_crate_backend_exe_ret42_$$" +TMP_JSON="/tmp/ny_crate_backend_exe_ret42_$$.json" +echo "$JSON" > "$TMP_JSON" + +if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then + if [[ -x "$APP" ]]; then + set +e + "$APP" >/dev/null 2>&1; rc=$? + set -e + if [ "$rc" -eq 42 ]; then + echo "[PASS] s3_backend_selector_crate_exe_return42_canary_vm" + rm -f "$APP" "$TMP_JSON" 2>/dev/null || true + exit 0 + fi + fi +fi +echo "[SKIP] s3_backend_selector_crate_exe_return42_canary_vm (rc mapping not active)" >&2 +rm -f "$APP" "$TMP_JSON" 2>/dev/null || true +exit 0 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_return_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_return_canary_vm.sh new file mode 100644 index 00000000..7584c15d --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_return_canary_vm.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" + +# Prebuild required tools/libraries +(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true +(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true + +# Minimal MIR v1 JSON that returns 0. +JSON='{ + "schema_version": 1, + "functions": [ + {"name":"ny_main","blocks":[ + {"id":0,"inst":[ + {"op":"const","dst":1,"ty":"i64","value":0}, + {"op":"ret","value":1} + ]} + ]} + ] +}' + +APP="/tmp/ny_crate_backend_exe_ret_$$" +TMP_JSON="/tmp/ny_crate_backend_exe_ret_$$.json" +echo "$JSON" > "$TMP_JSON" + +if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then + if [[ -x "$APP" ]]; then + set +e + "$APP" >/dev/null 2>&1; rc=$? + set -e + if [ "$rc" -eq 0 ]; then + echo "[PASS] s3_backend_selector_crate_exe_return_canary_vm" + rm -f "$APP" "$TMP_JSON" 2>/dev/null || true + exit 0 + fi + fi +fi +echo "[FAIL] s3_backend_selector_crate_exe_return_canary_vm" >&2 +rm -f "$APP" "$TMP_JSON" 2>/dev/null || true +exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_shift_left_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_shift_left_canary_vm.sh new file mode 100644 index 00000000..544db6ef --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_shift_left_canary_vm.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" + +(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true +(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true + +JSON='{ + "schema_version": 1, + "functions": [ + {"name":"ny_main","blocks":[ + {"id":0,"inst":[ + {"op":"const","dst":1,"ty":"i64","value":4}, + {"op":"const","dst":2,"ty":"i64","value":1}, + {"op":"binop","operation":"<<","lhs":1,"rhs":2,"dst":3}, + {"op":"ret","value":3} + ]} + ]} + ] +}' + +APP="/tmp/ny_crate_backend_exe_shl_$$" +TMP_JSON="/tmp/ny_crate_backend_exe_shl_$$.json" +echo "$JSON" > "$TMP_JSON" + +if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then + if [[ -x "$APP" ]]; then + set +e + "$APP" >/dev/null 2>&1; rc=$? + set -e + if [ "$rc" -eq 8 ]; then + echo "[PASS] s3_backend_selector_crate_exe_shift_left_canary_vm" + rm -f "$APP" "$TMP_JSON" 2>/dev/null || true + exit 0 + fi + fi +fi +echo "[FAIL] s3_backend_selector_crate_exe_shift_left_canary_vm" >&2 +rm -f "$APP" "$TMP_JSON" 2>/dev/null || true +exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_shift_right_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_shift_right_canary_vm.sh new file mode 100644 index 00000000..c7173530 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_shift_right_canary_vm.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" + +(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true +(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true + +JSON='{ + "schema_version": 1, + "functions": [ + {"name":"ny_main","blocks":[ + {"id":0,"inst":[ + {"op":"const","dst":1,"ty":"i64","value":8}, + {"op":"const","dst":2,"ty":"i64","value":1}, + {"op":"binop","operation":">>","lhs":1,"rhs":2,"dst":3}, + {"op":"ret","value":3} + ]} + ]} + ] +}' + +APP="/tmp/ny_crate_backend_exe_shr_$$" +TMP_JSON="/tmp/ny_crate_backend_exe_shr_$$.json" +echo "$JSON" > "$TMP_JSON" + +if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then + if [[ -x "$APP" ]]; then + set +e + "$APP" >/dev/null 2>&1; rc=$? + set -e + if [ "$rc" -eq 4 ]; then + echo "[PASS] s3_backend_selector_crate_exe_shift_right_canary_vm" + rm -f "$APP" "$TMP_JSON" 2>/dev/null || true + exit 0 + fi + fi +fi +echo "[FAIL] s3_backend_selector_crate_exe_shift_right_canary_vm" >&2 +rm -f "$APP" "$TMP_JSON" 2>/dev/null || true +exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2120/native_backend_binop_add_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2120/native_backend_binop_add_canary_vm.sh new file mode 100644 index 00000000..e3383395 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2120/native_backend_binop_add_canary_vm.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +BIN_BUILDER="$ROOT/tools/ny_mir_builder.sh" + +if ! command -v llc >/dev/null 2>&1; then + echo "[SKIP] native_backend_binop_add_canary_vm (llc not found)" >&2 + exit 0 +fi + +# Build NyRT quietly (link step) +(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true + +JSON='{ + "schema_version": 1, + "functions": [ + {"name":"ny_main","blocks":[ + {"id":0,"inst":[ + {"op":"const","dst":1,"ty":"i64","value":40}, + {"op":"const","dst":2,"ty":"i64","value":2}, + {"op":"binop","dst":3,"operation":"Add","lhs":1,"rhs":2}, + {"op":"ret","value":3} + ]} + ]} + ] +}' + +TMP_JSON="/tmp/native_binop_add_$$.json"; echo "$JSON" > "$TMP_JSON" +APP="/tmp/native_binop_add_$$" + +set +e +NYASH_LLVM_BACKEND=native NYASH_LLVM_SKIP_BUILD=1 bash "$BIN_BUILDER" --in "$TMP_JSON" --emit exe -o "$APP" >/dev/null 2>&1 +RC_BUILD=$? +set -e +if [ "$RC_BUILD" -ne 0 ]; then + echo "[SKIP] native_backend_binop_add_canary_vm (native builder failed)" >&2 + rm -f "$TMP_JSON" "$APP"; exit 0 +fi + +set +e +"$APP" >/dev/null 2>&1; rc=$? +set -e +rm -f "$TMP_JSON" "$APP" 2>/dev/null || true +if [ "$rc" -eq 42 ]; then + echo "[PASS] native_backend_binop_add_canary_vm" + exit 0 +fi +echo "[FAIL] native_backend_binop_add_canary_vm (rc=$rc)" >&2 +exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2120/native_backend_branch_eq_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2120/native_backend_branch_eq_canary_vm.sh new file mode 100644 index 00000000..1cdeb334 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2120/native_backend_branch_eq_canary_vm.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +BIN_BUILDER="$ROOT/tools/ny_mir_builder.sh" + +if ! command -v llc >/dev/null 2>&1; then + echo "[SKIP] native_backend_branch_eq_canary_vm (llc not found)" >&2 + exit 0 +fi + +(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true + +# Compare false (5==6) -> branch to else (ret 42) +JSON='{ + "schema_version": 1, + "functions": [ + {"name":"ny_main","blocks":[ + {"id":0,"inst":[ + {"op":"const","dst":1,"ty":"i64","value":5}, + {"op":"const","dst":2,"ty":"i64","value":42}, + {"op":"compare","dst":3,"operation":"==","lhs":1,"rhs":2}, + {"op":"branch","cond":3, "then":1, "else":2} + ]}, + {"id":1,"inst":[ + {"op":"ret","value":1} + ]}, + {"id":2,"inst":[ + {"op":"ret","value":2} + ]} + ]} + ] +}' + +TMP_JSON="/tmp/native_branch_eq_$$.json"; echo "$JSON" > "$TMP_JSON" +APP="/tmp/native_branch_eq_$$" + +set +e +NYASH_LLVM_BACKEND=native NYASH_LLVM_SKIP_BUILD=1 bash "$BIN_BUILDER" --in "$TMP_JSON" --emit exe -o "$APP" >/dev/null 2>&1 +RC_BUILD=$? +set -e +if [ "$RC_BUILD" -ne 0 ]; then + echo "[SKIP] native_backend_branch_eq_canary_vm (native builder failed)" >&2 + rm -f "$TMP_JSON" "$APP"; exit 0 +fi + +set +e +"$APP" >/dev/null 2>&1; rc=$? +set -e +rm -f "$TMP_JSON" "$APP" 2>/dev/null || true +if [ "$rc" -eq 42 ]; then + echo "[PASS] native_backend_branch_eq_canary_vm" + exit 0 +fi +echo "[FAIL] native_backend_branch_eq_canary_vm (rc=$rc)" >&2 +exit 1 diff --git a/tools/smokes/v2/profiles/quick/core/phase2120/native_backend_compare_eq_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2120/native_backend_compare_eq_canary_vm.sh new file mode 100644 index 00000000..5e38adf5 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2120/native_backend_compare_eq_canary_vm.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +BIN_BUILDER="$ROOT/tools/ny_mir_builder.sh" + +if ! command -v llc >/dev/null 2>&1; then + echo "[SKIP] native_backend_compare_eq_canary_vm (llc not found)" >&2 + exit 0 +fi + +(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true + +JSON='{ + "schema_version": 1, + "functions": [ + {"name":"ny_main","blocks":[ + {"id":0,"inst":[ + {"op":"const","dst":1,"ty":"i64","value":5}, + {"op":"const","dst":2,"ty":"i64","value":5}, + {"op":"compare","dst":3,"operation":"==","lhs":1,"rhs":2}, + {"op":"ret","value":3} + ]} + ]} + ] +}' + +TMP_JSON="/tmp/native_cmp_eq_$$.json"; echo "$JSON" > "$TMP_JSON" +APP="/tmp/native_cmp_eq_$$" + +set +e +NYASH_LLVM_BACKEND=native NYASH_LLVM_SKIP_BUILD=1 bash "$BIN_BUILDER" --in "$TMP_JSON" --emit exe -o "$APP" >/dev/null 2>&1 +RC_BUILD=$? +set -e +if [ "$RC_BUILD" -ne 0 ]; then + echo "[SKIP] native_backend_compare_eq_canary_vm (native builder failed)" >&2 + rm -f "$TMP_JSON" "$APP"; exit 0 +fi + +set +e +"$APP" >/dev/null 2>&1; rc=$? +set -e +rm -f "$TMP_JSON" "$APP" 2>/dev/null || true +if [ "$rc" -eq 1 ]; then + echo "[PASS] native_backend_compare_eq_canary_vm" + exit 0 +fi +echo "[FAIL] native_backend_compare_eq_canary_vm (rc=$rc)" >&2 +exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2120/native_backend_return42_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2120/native_backend_return42_canary_vm.sh new file mode 100644 index 00000000..fb9f17c3 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2120/native_backend_return42_canary_vm.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +BIN_BUILDER="$ROOT/tools/ny_mir_builder.sh" + +# Require llc (native path) +if ! command -v llc >/dev/null 2>&1; then + echo "[SKIP] native_backend_return42_canary_vm (llc not found)" >&2 + exit 0 +fi + +# Prebuild NyRT (for linking) +(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true + +JSON='{ + "schema_version": 1, + "functions": [ + {"name":"ny_main","blocks":[ + {"id":0,"inst":[ + {"op":"const","dst":1,"ty":"i64","value":42}, + {"op":"ret","value":1} + ]} + ]} + ] +}' + +TMP_JSON="/tmp/native_ret42_$$.json"; echo "$JSON" > "$TMP_JSON" +APP="/tmp/native_ret42_$$" + +if ! NYASH_LLVM_BACKEND=native NYASH_LLVM_SKIP_BUILD=1 bash "$BIN_BUILDER" --in "$TMP_JSON" --emit exe -o "$APP" >/dev/null 2>&1; then + echo "[SKIP] native_backend_return42_canary_vm (native builder failed)" >&2 + rm -f "$TMP_JSON" "$APP"; exit 0 +fi +set +e +"$APP" >/dev/null 2>&1; rc=$? +set -e +rm -f "$TMP_JSON" "$APP" 2>/dev/null || true +if [ "$rc" -eq 42 ]; then + echo "[PASS] native_backend_return42_canary_vm" + exit 0 +fi +echo "[FAIL] native_backend_return42_canary_vm" >&2 +exit 1 diff --git a/tools/smokes/v2/profiles/quick/core/phase2211/tlv_shim_parity_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2211/tlv_shim_parity_canary_vm.sh new file mode 100644 index 00000000..abef9a66 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2211/tlv_shim_parity_canary_vm.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -euo pipefail + +source "$(dirname "$0")/../../../../lib/test_runner.sh" +require_env >/dev/null || exit 2 + +# Build nyash with tlv-shim feature (even if we run OFF for parity) +( cd "$NYASH_ROOT" && cargo build -q --release -p nyash-rust --features tlv-shim ) + +CODE=' +static box Main { + main() { + local m = new MapBox() + m.set("k", "v") + print(m.get("k")) + return 0 + } +} +' + +o1=$(HAKO_TLV_SHIM=0 run_nyash_vm -c "$CODE" 2>&1 | tr -d '\r') +o2=$(HAKO_TLV_SHIM=1 run_nyash_vm -c "$CODE" 2>&1 | tr -d '\r') + +# Strip shim trace if any to compare pure program output +o1p=$(printf "%s\n" "$o1" | awk '!/^\[tlv\/shim:/') +o2p=$(printf "%s\n" "$o2" | awk '!/^\[tlv\/shim:/') + +if diff -u <(printf "%s\n" "$o1p") <(printf "%s\n" "$o2p") >/dev/null; then + echo "[PASS] tlv_shim_parity_canary_vm" + exit 0 +fi +echo "[FAIL] tlv_shim_parity_canary_vm" >&2 +echo "--- OFF ---" >&2; echo "$o1" >&2 +echo "--- ON ----" >&2; echo "$o2" >&2 +exit 1 +