Phase 22.x WIP: LLVM backend improvements + MIR builder enhancements

LLVM backend improvements:
- Add native LLVM backend support (NYASH_LLVM_BACKEND=native)
- Add crate backend selector with priority (crate > llvmlite)
- Add native_llvm_builder.py for native IR generation
- Add NYASH_LLVM_NATIVE_TRACE=1 for IR dump

MIR builder enhancements:
- Refactor lower_if_compare_* boxes for better code generation
- Refactor lower_return_* boxes for optimized returns
- Refactor lower_loop_* boxes for loop handling
- Refactor lower_method_* boxes for method calls
- Update pattern_util_box for better pattern matching

Smoke tests:
- Add phase2100 S3 backend selector tests (17 new tests)
- Add phase2120 native backend tests (4 new tests)
- Add phase2034 MIR builder internal tests (2 new tests)
- Add phase2211 TLV shim parity test

Documentation:
- Update ENV_VARS.md with LLVM backend variables
- Update CURRENT_TASK.md with progress
- Update README.md and CHANGELOG.md

Config:
- Add NYASH_LLVM_BACKEND env support in src/config/env.rs
- Update ny_mir_builder.sh for backend selection
- Update dispatch.rs for backend routing

Tools:
- Add tools/native_llvm_builder.py
- Update smokes/v2/profiles/quick/core/phase2100/run_all.sh

Known: Many Hako builder internal files modified for optimization
This commit is contained in:
nyash-codex
2025-11-09 23:40:36 +09:00
parent fb6129183d
commit f6c5dc9e43
65 changed files with 1965 additions and 434 deletions

View File

@ -3,6 +3,14 @@
This changelog tracks highlevel milestones while Core MIR and Phase 12 evolve. For detailed perfile history, see git log and docs under `docs/development/roadmap/`.
## 20250906
### 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`): StageB 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 envguarded normalization in nyllvmc (no default behavior changes).
- Core13 flip complete: code/tests enforce Core13 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: step50 marked done; DEV quickstart points to Core13 reference.

View File

@ -1,4 +1,26 @@
# Current Task — Phase 21.4Hako Parser → Analyzer / SelfHost
# Current Task — Phase 21.10LLVM line crate backend print EXE
Status (22.3 wrap)
- 22.3 締め: 最小Cランタイム設計/Cシンボル整合nyash.console.*→nyash_console_*)を反映。
- Hako-first MIR emit は wrapper 経由で安定StageB 出力の RC 混入を抑止、Hako→失敗時は Rust CLI にフォールバック)。
- 緑条件は quick 代表セット + phase2231 canaryrc=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) Ccore 一点通しMap.set+ parity維持既定OFF
- feature+ENV で noop 経路を通し、ON/OFF parity をカナリアで検証。
目的(このフェーズで到達するゴール)
- Hako ParserMVPで AST JSON v0 を出力し、Analyzer の一次入力に採用text は fallback 維持)。
@ -41,6 +63,10 @@ Toggles quicklist
- EXEfirst: `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`(受理+警告、一度だけ)
- GateC: 主 `NYASH_GATE_C_CORE`、alias `HAKO_GATE_C_CORE`(受理+警告、一度だけ)
22.1 progress (today)
- TLV配線最小導線・既定OFF

View File

@ -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 (Hakofirst helper)
- Generate MIR(JSON) from a Hako file using the StageB 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 StageB 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)

View File

@ -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<PathBuf> = 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::<JsonValue>(&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::<serde_json::Value>(&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<String> {
// 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);
}

View File

@ -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.

View File

@ -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 StageB → 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,6 +95,11 @@ 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_*` に正規化される(ドット→アンダースコア)。
@ -101,3 +110,19 @@ Kernel Minimal C Runtime (Phase 22.3 — design)
- NYASH_KERNEL_C_MIN=0|1
- Reserved toggle for enabling the minimal C runtime shimsdesignstage; 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 onetime 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; onetime warning): `HAKO_LLVM_OPT_LEVEL`
- GateC (Core direct route)
- Primary: `NYASH_GATE_C_CORE`
- Accepted alias (deprecated; onetime 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.

View File

@ -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 }

View File

@ -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))

View File

@ -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))

View File

@ -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))

View File

@ -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

View File

@ -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)

View File

@ -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()

View File

@ -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 <varname> = (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)
}

View File

@ -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 }
}

View File

@ -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) }
}
}
}

View File

@ -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)

View File

@ -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" }

View File

@ -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
}
}

View File

@ -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)

View File

@ -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
}
}

View File

@ -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 }

View File

@ -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 }

View File

@ -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))

View File

@ -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))
}

View File

@ -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 }

View File

@ -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 }

View File

@ -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

View File

@ -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 }

View File

@ -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
// Prefer exact-name Local lookups via PatternUtilBox
// Int / Bool / Float / String (in this order)
{
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)
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 }
}
{
local vb = PatternUtilBox.find_local_bool_before(s, namev, k_m)
if vb != null { b0.push(MirSchemaBox.inst_const(next_id, vb)) args_ids.push(next_id) next_id = next_id + 1 }
}
if nm2 != null && nm2 == namev { last2 = kL2 }
pos2 = kL2 + 1
{
local vf = PatternUtilBox.find_local_float_before(s, namev, k_m)
if vf != null { b0.push(MirSchemaBox.inst_const_f64(next_id, vf)) args_ids.push(next_id) next_id = next_id + 1 }
}
if 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 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 }
}
}
}

View File

@ -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 }

View File

@ -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 }

View File

@ -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(jj<nn){ if (""+s).substring(jj,jj+1)=="\"" {break} jj=jj+1 }
if (""+s).substring(ii,jj)==name { last=k }
}
pos=k+1
}
if last<0 { return null }
local next=JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last+1)
if next<0||next>before_pos{ next=before_pos }
local ts=(""+s).indexOf("\"type\":\"String\"", last)
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(jj<nn){ if (""+s).substring(jj,jj+1)=="\"" {break} jj=jj+1 }
if (""+s).substring(ii,jj)==name { last=k }
}
pos=k+1
}
if last<0 { return null }
local next=JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last+1)
if next<0||next>before_pos{ next=before_pos }
local tf=(""+s).indexOf("\"type\":\"Float\"", last)
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) {

View File

@ -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<RwLock<NyashEnv>> = OnceCell::new();
static WARNED_ALIASES: OnceCell<Mutex<HashSet<String>>> = 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: デフォルトONusing 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 BlockPostfix 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()
}
/// GateC(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
}

View File

@ -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)

View File

@ -45,6 +45,22 @@ 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 ('==','!=','<','>','<=','>='):

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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. Backwardcompat 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 {

View File

@ -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<id>:
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)

View File

@ -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,10 +61,13 @@ if [[ -z "$OUT" ]]; then
esac
fi
# 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 neededskip allowed
LLVM_FEATURE=${NYASH_LLVM_FEATURE:-llvm}
@ -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

View File

@ -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

View File

@ -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

View File

@ -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."

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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=$?

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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