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/`. 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 ## 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. - 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. - 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 維持)。 - Hako ParserMVPで AST JSON v0 を出力し、Analyzer の一次入力に採用text は fallback 維持)。
@ -41,6 +63,10 @@ Toggles quicklist
- EXEfirst: `SMOKES_ENABLE_SELFHOST=1`既定OFF - EXEfirst: `SMOKES_ENABLE_SELFHOST=1`既定OFF
- TLV: `--features tlv-shim` + `HAKO_TLV_SHIM=1`既定OFF/配線は無害な identity - TLV: `--features tlv-shim` + `HAKO_TLV_SHIM=1`既定OFF/配線は無害な identity
- Using SSOT: `HAKO_USING_SSOT=1`MVP は現行解決ロジックを経由しつつタグ出力) - 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) 22.1 progress (today)
- TLV配線最小導線・既定OFF - TLV配線最小導線・既定OFF

View File

@ -4,6 +4,18 @@
**A Seriously-Crafted Hobby Language** **A Seriously-Crafted Hobby Language**
**From Zero to Native Binary in 20 Days - The AI-Powered Language Revolution** **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)* *[🇯🇵 日本語版はこちら / 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) [![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 anyhow::{bail, Context, Result};
use clap::{ArgAction, Parser}; use clap::{ArgAction, Parser};
use serde_json::Value as JsonValue;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command( #[command(
@ -86,29 +87,59 @@ fn main() -> Result<()> {
return Ok(()); 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 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 input_path = if args.infile == "-" {
let mut buf = String::new(); let mut buf = String::new();
std::io::stdin() std::io::stdin()
.read_to_string(&mut buf) .read_to_string(&mut buf)
.context("reading MIR JSON from stdin")?; .context("reading MIR JSON from stdin")?;
// Basic sanity check that it's JSON let mut val: serde_json::Value =
let _: serde_json::Value =
serde_json::from_str(&buf).context("stdin does not contain valid JSON")?; 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 tmp = std::env::temp_dir().join("ny_llvmc_stdin.json");
let mut f = File::create(&tmp).context("create temp json file")?; 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()); temp_path = Some(tmp.clone());
tmp tmp
} else { } 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() { if !input_path.exists() {
bail!("input JSON not found: {}", input_path.display()); 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 // Produce object first
let obj_path = if emit_exe { let obj_path = if emit_exe {
let mut p = args.out.clone(); let mut p = args.out.clone();
@ -118,6 +149,20 @@ fn main() -> Result<()> {
args.out.clone() 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(|| { run_harness_in(&harness_path, &input_path, &obj_path).with_context(|| {
format!( format!(
"failed to compile MIR JSON via harness: {}", "failed to compile MIR JSON via harness: {}",
@ -144,6 +189,93 @@ fn main() -> Result<()> {
Ok(()) 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<()> { fn run_harness_dummy(harness: &Path, out: &Path) -> Result<()> {
ensure_python()?; ensure_python()?;
let mut cmd = Command::new("python3"); let mut cmd = Command::new("python3");
@ -182,10 +314,13 @@ fn ensure_python() -> Result<()> {
} }
fn propagate_opt_level(cmd: &mut Command) { fn propagate_opt_level(cmd: &mut Command) {
let level = env::var("HAKO_LLVM_OPT_LEVEL") let hako = env::var("HAKO_LLVM_OPT_LEVEL").ok();
.ok() let nyash = env::var("NYASH_LLVM_OPT_LEVEL").ok();
.or_else(|| env::var("NYASH_LLVM_OPT_LEVEL").ok()); let level = nyash.clone().or(hako.clone());
if let Some(level) = level { 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("HAKO_LLVM_OPT_LEVEL", &level);
cmd.env("NYASH_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; return 0;
} }
// Optional minimal stubs (not used by default; reserved for future reps) // Note: Additional array/map stubs intentionally omitted to avoid symbol
long nyash_array_birth_h(void) { return 1; } // clashes with the full NyKernel when linked together. Keep this file minimal
long nyash_array_length_h(long handle) { (void)handle; return 0; } // (console only) for print canaries.
long nyash_map_birth_h(void) { return 1; }
long nyash_map_size_h(long handle) { (void)handle; return 0; }

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. 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 - HAKO_USING_SSOT=0|1
- Enables the SSOT resolver gate in the runner pipeline. - 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. - 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`). - `crate`: uses `./target/release/ny-llvmc` (build with `cargo build -p nyash-llvm-compiler --release`).
- `native`: reserved for future Hako-native builder. - `native`: reserved for future Hako-native builder.
- Linking extras for `--emit exe`: pass via `HAKO_AOT_LDFLAGS` (e.g., `-static`), `ny-llvmc` consumes `--libs`. - 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) Name mapping note (EXE link convenience)
- nyash.console.* は C リンク時にシンボル名 `nyash_console_*` に正規化される(ドット→アンダースコア)。 - nyash.console.* は C リンク時にシンボル名 `nyash_console_*` に正規化される(ドット→アンダースコア)。
@ -101,3 +110,19 @@ Kernel Minimal C Runtime (Phase 22.3 — design)
- NYASH_KERNEL_C_MIN=0|1 - NYASH_KERNEL_C_MIN=0|1
- Reserved toggle for enabling the minimal C runtime shimsdesignstage; defaults OFF - Reserved toggle for enabling the minimal C runtime shimsdesignstage; defaults OFF
- Build: `cargo build --release -p nyash-kernel-min-c`not linked by default - 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 { static box LowerIfCompareBox {
try_lower(program_json) { try_lower(program_json) {
local s = "" + 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 } if k_if < 0 { return null }
// cond Compare // 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 } 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 } if k_op < 0 { return null }
local op = JsonFragBox.read_string_after(s, k_op + 5) local op = JsonFragBox.read_string_after(s, k_op + 5)
if op == null { return null } if op == null { return null }
if !(op == "<" || op == ">" || op == "<=" || op == ">=" || op == "==" || op == "!=") { return null } if !(op == "<" || op == ">" || op == "<=" || op == ">=" || op == "==" || op == "!=") { return null }
// lhs/rhs ints // 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 } 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 } 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 } if kv_lhs < 0 { return null }
local lhs_val = JsonFragBox.read_int_after(s, kv_lhs + 8) local lhs_val = JsonFragBox.read_int_after(s, kv_lhs + 8)
if lhs_val == null { return null } 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 } 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 } 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 } if kv_rhs < 0 { return null }
local rhs_val = JsonFragBox.read_int_after(s, kv_rhs + 8) local rhs_val = JsonFragBox.read_int_after(s, kv_rhs + 8)
if rhs_val == null { return null } if rhs_val == null { return null }
// then/else return ints // 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 } 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 } 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 } 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 } if kv_then < 0 { return null }
local then_val = JsonFragBox.read_int_after(s, kv_then + 8) local then_val = JsonFragBox.read_int_after(s, kv_then + 8)
if then_val == null { return null } 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 } 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 } 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 } 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 } if kv_else < 0 { return null }
local else_val = JsonFragBox.read_int_after(s, kv_else + 8) local else_val = JsonFragBox.read_int_after(s, kv_else + 8)
if else_val == null { return null } if else_val == null { return null }

View File

@ -7,15 +7,15 @@ using selfhost.shared.mir.schema as MirSchemaBox
static box LowerIfCompareFoldBinIntsBox { static box LowerIfCompareFoldBinIntsBox {
_fold_bin_ints(s, k_bin_start) { _fold_bin_ints(s, k_bin_start) {
// expects: {"type":"Binary","op":"+|-|*|/","lhs":{"type":"Int","value":L},"rhs":{"type":"Int","value":R}} // 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) local iop = kop + 6; local op = s.substring(iop, iop+1)
if !(op == "+" || op == "-" || op == "*" || op == "/") { return null } if !(op == "+" || op == "-" || op == "*" || op == "/") { return null }
local kli = s.indexOf("\"type\":\"Int\"", k_bin_start); if kli < 0 { return null } local kli = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_bin_start); if kli < 0 { return null }
local kvl = s.indexOf("\"value\":", kli); if kvl < 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 } local l = JsonFragBox.read_int_after(s, kvl + 8); if l == null { return null }
// rhs int // rhs int
local kri = s.indexOf("\"type\":\"Int\"", kli + 1); if kri < 0 { return null } local kri = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", kli + 1); if kri < 0 { return null }
local kv2 = s.indexOf("\"value\":", kri); if kv2 < 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 } local r = JsonFragBox.read_int_after(s, kv2 + 8); if r == null { return null }
// compute // compute
local li = 0; local ri = 0; // string to int by simple parse (assume i64 fits) 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 // node may be Int, Binary(Int,Int), or Var with Local Int before if_pos
if node_pos < 0 { return null } if node_pos < 0 { return null }
// Int // Int
if s.indexOf("\"type\":\"Int\"", node_pos) == node_pos { // best-effort if JsonFragBox.index_of_from(s, "\"type\":\"Int\"", node_pos) == node_pos { // best-effort
local kv = s.indexOf("\"value\":", node_pos); if kv < 0 { return null } local kv = JsonFragBox.index_of_from(s, "\"value\":", node_pos); if kv < 0 { return null }
return JsonFragBox.read_int_after(s, kv + 8) return JsonFragBox.read_int_after(s, kv + 8)
} }
// Binary // 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) return me._fold_bin_ints(s, node_pos)
} }
// Var(name) // Var(name)
if s.indexOf("\"type\":\"Var\"", node_pos) == node_pos { if JsonFragBox.index_of_from(s, "\"type\":\"Var\"", node_pos) == node_pos {
local kn = s.indexOf("\"name\":\"", node_pos); if kn < 0 { return null } 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 } local name = JsonFragBox.read_string_after(s, kn + 5); if name == null { return null }
// find last matching Local Int before if_pos via util // find last matching Local Int before if_pos via util
return PatternUtilBox.find_local_int_before(s, name, if_pos) return PatternUtilBox.find_local_int_before(s, name, if_pos)
@ -51,29 +51,29 @@ static box LowerIfCompareFoldBinIntsBox {
} }
try_lower(program_json){ try_lower(program_json){
local s = "" + program_json local s = "" + program_json
local k_if = s.indexOf("\"type\":\"If\""); if k_if < 0 { return null } 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); if k_cmp < 0 { return null } 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 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 } local op = PatternUtilBox.map_cmp(sym); if op == null { return null }
// locate lhs/rhs node starts (Var/Int/Binary) // locate lhs/rhs node starts (Var/Int/Binary)
local klhs = s.indexOf("\"lhs\":{", k_cmp); if klhs < 0 { return null } local klhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp); if klhs < 0 { return null }
local krhs = s.indexOf("\"rhs\":{", k_cmp); if krhs < 0 { return null } local krhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp); if krhs < 0 { return null }
local lhs_pos = klhs + 6 local lhs_pos = klhs + 6
local rhs_pos = krhs + 6 local rhs_pos = krhs + 6
local lhs_val = me._resolve_side_int(s, lhs_pos, k_if) local lhs_val = me._resolve_side_int(s, lhs_pos, k_if)
local rhs_val = me._resolve_side_int(s, rhs_pos, k_if) local rhs_val = me._resolve_side_int(s, rhs_pos, k_if)
if lhs_val == null || rhs_val == null { return null } if lhs_val == null || rhs_val == null { return null }
// then/else Return(Int) // then/else Return(Int)
local kth = s.indexOf("\"then\":", k_if); if kth < 0 { return null } local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if); if kth < 0 { return null }
local rt1 = s.indexOf("\"type\":\"Return\"", kth); if rt1 < 0 { return null } local rt1 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth); if rt1 < 0 { return null }
local ti1 = s.indexOf("\"type\":\"Int\"", rt1); if ti1 < 0 { return null } local ti1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt1); if ti1 < 0 { return null }
local kv1 = s.indexOf("\"value\":", ti1); if kv1 < 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 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 kel = JsonFragBox.index_of_from(s, "\"else\":", k_if); if kel < 0 { return null }
local rt2 = s.indexOf("\"type\":\"Return\"", kel); if rt2 < 0 { return null } local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kel); if rt2 < 0 { return null }
local ti2 = s.indexOf("\"type\":\"Int\"", rt2); if ti2 < 0 { return null } local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2); if ti2 < 0 { return null }
local kv2b = s.indexOf("\"value\":", ti2); if kv2b < 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 } local else_v = JsonFragBox.read_int_after(s, kv2b + 8); if else_v == null { return null }
// Build MIR // Build MIR
local b0 = new ArrayBox(); b0.push(MirSchemaBox.inst_const(1, lhs_val)); b0.push(MirSchemaBox.inst_const(2, rhs_val)); b0.push(MirSchemaBox.inst_compare(op,1,2,3)); b0.push(MirSchemaBox.inst_branch(3,1,2)) local 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 { static box LowerIfCompareFoldVarIntBox {
_fold_bin_varint(s, k_bin, if_pos) { _fold_bin_varint(s, k_bin, if_pos) {
// Binary with one Var and one Int; resolve Var via Local and compute result // 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) local op = JsonFragBox.read_string_after(s, kop + 5)
if !(op=="+"||op=="-"||op=="*"||op=="/") { return null } if !(op=="+"||op=="-"||op=="*"||op=="/") { return null }
local klv = s.indexOf("\"lhs\":{\"type\":\"Var\"", k_bin) local klv = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\"", k_bin)
local kli = s.indexOf("\"lhs\":{\"type\":\"Int\"", k_bin) local kli = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Int\"", k_bin)
local krv = s.indexOf("\"rhs\":{\"type\":\"Var\"", k_bin) local krv = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\"", k_bin)
local kri = s.indexOf("\"rhs\":{\"type\":\"Int\"", k_bin) local kri = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Int\"", k_bin)
local vval = null; local ival = null local vval = null; local ival = null
if klv >= 0 && kri >= 0 { 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) local name = JsonFragBox.read_string_after(s, kn + 7)
vval = PatternUtilBox.find_local_int_before(s, name, if_pos) 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) ival = JsonFragBox.read_int_after(s, kv + 8)
} else if kli >= 0 && krv >= 0 { } 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) 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) local name2 = JsonFragBox.read_string_after(s, kn2 + 7)
vval = PatternUtilBox.find_local_int_before(s, name2, if_pos) vval = PatternUtilBox.find_local_int_before(s, name2, if_pos)
} }
@ -36,17 +36,17 @@ static box LowerIfCompareFoldVarIntBox {
} }
_resolve_side(s, node_pos, if_pos) { _resolve_side(s, node_pos, if_pos) {
// Try Int // Try Int
if s.indexOf("\"type\":\"Int\"", node_pos) == node_pos { if JsonFragBox.index_of_from(s, "\"type\":\"Int\"", node_pos) == node_pos {
local kv = s.indexOf("\"value\":", node_pos); if kv < 0 { return null } local kv = JsonFragBox.index_of_from(s, "\"value\":", node_pos); if kv < 0 { return null }
return JsonFragBox.read_int_after(s, kv + 8) return JsonFragBox.read_int_after(s, kv + 8)
} }
// Binary(Var,Int) or (Int,Var) // 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) return me._fold_bin_varint(s, node_pos, if_pos)
} }
// Var → Local Int // Var → Local Int
if s.indexOf("\"type\":\"Var\"", node_pos) == node_pos { if JsonFragBox.index_of_from(s, "\"type\":\"Var\"", node_pos) == node_pos {
local kn = s.indexOf("\"name\":", node_pos); if kn < 0 { return null } local kn = JsonFragBox.index_of_from(s, "\"name\":", node_pos); if kn < 0 { return null }
local name = JsonFragBox.read_string_after(s, kn + 7) local name = JsonFragBox.read_string_after(s, kn + 7)
return PatternUtilBox.find_local_int_before(s, name, if_pos) return PatternUtilBox.find_local_int_before(s, name, if_pos)
} }
@ -54,26 +54,26 @@ static box LowerIfCompareFoldVarIntBox {
} }
try_lower(program_json){ try_lower(program_json){
local s = "" + program_json local s = "" + program_json
local k_if = s.indexOf("\"type\":\"If\""); if k_if < 0 { return null } 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); if k_cmp < 0 { return null } 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 op_sym = JsonFragBox.read_string_after(s, k_op + 5) local op_sym = JsonFragBox.read_string_after(s, k_op + 5)
local op = PatternUtilBox.map_cmp(op_sym); if op == null { return null } 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 klhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp); if klhs < 0 { return null }
local krhs = s.indexOf("\"rhs\":{", k_cmp); if krhs < 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 lhs = me._resolve_side(s, klhs+6, k_if)
local rhs = me._resolve_side(s, krhs+6, k_if) local rhs = me._resolve_side(s, krhs+6, k_if)
if lhs == null || rhs == null { return null } if lhs == null || rhs == null { return null }
// then/else Return(Int) // then/else Return(Int)
local kth = s.indexOf("\"then\":", k_if); if kth < 0 { return null } local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if); if kth < 0 { return null }
local rt1 = s.indexOf("\"type\":\"Return\"", kth); if rt1 < 0 { return null } local rt1 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth); if rt1 < 0 { return null }
local ti1 = s.indexOf("\"type\":\"Int\"", rt1); if ti1 < 0 { return null } local ti1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt1); if ti1 < 0 { return null }
local kv1 = s.indexOf("\"value\":", ti1); if kv1 < 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 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 kel = JsonFragBox.index_of_from(s, "\"else\":", k_if); if kel < 0 { return null }
local rt2 = s.indexOf("\"type\":\"Return\"", kel); if rt2 < 0 { return null } local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kel); if rt2 < 0 { return null }
local ti2 = s.indexOf("\"type\":\"Int\"", rt2); if ti2 < 0 { return null } local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2); if ti2 < 0 { return null }
local kv2b = s.indexOf("\"value\":", ti2); if kv2b < 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 } local ev = JsonFragBox.read_int_after(s, kv2b + 8); if ev == null { return null }
// Build // Build
local b0=new ArrayBox(); b0.push(MirSchemaBox.inst_const(1,lhs)); b0.push(MirSchemaBox.inst_const(2,rhs)); b0.push(MirSchemaBox.inst_compare(op,1,2,3)); b0.push(MirSchemaBox.inst_branch(3,1,2)) local 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 { static box LowerIfCompareVarIntBox {
try_lower(program_json){ try_lower(program_json){
local s = "" + program_json local s = "" + program_json
local k_if = s.indexOf("\"type\":\"If\""); if k_if < 0 { return null } // Locate If → Compare → op using robust index_of_from helpers
local k_cmp = s.indexOf("\"type\":\"Compare\"", k_if); if k_cmp < 0 { return null } local k_if = JsonFragBox.index_of_from(s, "\"type\":\"If\"", 0); if k_if < 0 { return null }
local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 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_sym = JsonFragBox.read_string_after(s, k_op + 5)
local op = PatternUtilBox.map_cmp(op_sym); if op == null { return null } local op = PatternUtilBox.map_cmp(op_sym); if op == null { return null }
// Var vs Int // Var vs Int
local klhs_var = s.indexOf("\"lhs\":{\"type\":\"Var\"", k_cmp) local klhs_var = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\"", k_cmp)
local krhs_int = s.indexOf("\"rhs\":{\"type\":\"Int\"", k_cmp) local krhs_int = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Int\"", k_cmp)
local aval=null; local bval=null local aval=null; local bval=null
if klhs_var >= 0 && krhs_int >= 0 { 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) local name = JsonFragBox.read_string_after(s, k_name + 7)
aval = PatternUtilBox.find_local_int_before(s, name, k_if) 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 { 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) bval = JsonFragBox.read_int_after(s, kv + 8)
} }
} else { } else {
// Int vs Var // Int vs Var
local klhs_int = s.indexOf("\"lhs\":{\"type\":\"Int\"", k_cmp) local klhs_int = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Int\"", k_cmp)
local krhs_var = s.indexOf("\"rhs\":{\"type\":\"Var\"", k_cmp) local krhs_var = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\"", k_cmp)
if klhs_int >= 0 && krhs_var >= 0 { 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 { 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) 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) local name2 = JsonFragBox.read_string_after(s, k_name2 + 7)
if name2 != null { bval = PatternUtilBox.find_local_int_before(s, name2, k_if) } if name2 != null { bval = PatternUtilBox.find_local_int_before(s, name2, k_if) }
} }
} }
if aval == null || bval == null { return null } if aval == null || bval == null { return null }
// then/else Return(Int) // then/else Return(Int)
local kth = s.indexOf("\"then\":", k_if); if kth < 0 { return null } local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if); if kth < 0 { return null }
local rt1 = s.indexOf("\"type\":\"Return\"", kth); if rt1 < 0 { return null } local rt1 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth); if rt1 < 0 { return null }
local ti1 = s.indexOf("\"type\":\"Int\"", rt1); if ti1 < 0 { return null } local ti1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt1); if ti1 < 0 { return null }
local kv_then = s.indexOf("\"value\":", ti1); if kv_then < 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 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 kel = JsonFragBox.index_of_from(s, "\"else\":", k_if); if kel < 0 { return null }
local rt2 = s.indexOf("\"type\":\"Return\"", kel); if rt2 < 0 { return null } local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kel); if rt2 < 0 { return null }
local ti2 = s.indexOf("\"type\":\"Int\"", rt2); if ti2 < 0 { return null } local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2); if ti2 < 0 { return null }
local kv_else = s.indexOf("\"value\":", ti2); if kv_else < 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 } local else_v = JsonFragBox.read_int_after(s, kv_else + 8); if else_v == null { return null }
// Build MIR // Build MIR
local b0=new ArrayBox(); b0.push(MirSchemaBox.inst_const(1,aval)); b0.push(MirSchemaBox.inst_const(2,bval)); b0.push(MirSchemaBox.inst_compare(op,1,2,3)); b0.push(MirSchemaBox.inst_branch(3,1,2)) local 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 { static box LowerIfCompareVarVarBox {
try_lower(program_json) { try_lower(program_json) {
local s = "" + 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 } 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 } if k_cmp < 0 { return null }
// LHS/RHS Var names // LHS/RHS Var names
local lhs_name = null 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 { 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) lhs_name = JsonFragBox.read_string_after(s, k_name_lhs + 7)
} }
local rhs_name = null 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 { 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) rhs_name = JsonFragBox.read_string_after(s, k_name_rhs + 7)
} }
if lhs_name == null || rhs_name == null { return null } 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) local bval = PatternUtilBox.find_local_int_before(s, rhs_name, k_if)
if aval == null || bval == null { return null } if aval == null || bval == null { return null }
// op map // 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) local sym = JsonFragBox.read_string_after(s, k_op + 5)
if sym == null { return null } if sym == null { return null }
local op = PatternUtilBox.map_cmp(sym) local op = PatternUtilBox.map_cmp(sym)
if op == null { return null } if op == null { return null }
// then/else Return(Int) // then/else Return(Int)
local kth = s.indexOf("\"then\":", k_if); if kth < 0 { return null } local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if); if kth < 0 { return null }
local rt1 = s.indexOf("\"type\":\"Return\"", kth); if rt1 < 0 { return null } local rt1 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth); if rt1 < 0 { return null }
local ti1 = s.indexOf("\"type\":\"Int\"", rt1); if ti1 < 0 { return null } local ti1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt1); if ti1 < 0 { return null }
local kv_then = s.indexOf("\"value\":", ti1); if kv_then < 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 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 kel = JsonFragBox.index_of_from(s, "\"else\":", k_if); if kel < 0 { return null }
local rt2 = s.indexOf("\"type\":\"Return\"", kel); if rt2 < 0 { return null } local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kel); if rt2 < 0 { return null }
local ti2 = s.indexOf("\"type\":\"Int\"", rt2); if ti2 < 0 { return null } local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2); if ti2 < 0 { return null }
local kv_else = s.indexOf("\"value\":", ti2); if kv_else < 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 } local else_val = JsonFragBox.read_int_after(s, kv_else + 8); if else_val == null { return null }
// Build MIR // Build MIR

View File

@ -19,53 +19,53 @@ using "hako.mir.builder.internal.pattern_util" as PatternUtilBox
static box LowerIfNestedBox { static box LowerIfNestedBox {
try_lower(program_json) { try_lower(program_json) {
local s = "" + 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 } 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 } 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 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 op1 = PatternUtilBox.map_cmp(op1s); if op1 == null { return null }
local klhs1 = s.indexOf("\"lhs\":{", k_cmp1); if klhs1 < 0 { return null } local klhs1 = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp1); if klhs1 < 0 { return null }
local ti11 = s.indexOf("\"type\":\"Int\"", klhs1); if ti11 < 0 { return null } local ti11 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", klhs1); if ti11 < 0 { return null }
local kv11 = s.indexOf("\"value\":", ti11); if kv11 < 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 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 krhs1 = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp1); if krhs1 < 0 { return null }
local ti12 = s.indexOf("\"type\":\"Int\"", krhs1); if ti12 < 0 { return null } local ti12 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", krhs1); if ti12 < 0 { return null }
local kv12 = s.indexOf("\"value\":", ti12); if kv12 < 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 } local rhs1 = JsonFragBox.read_int_after(s, kv12 + 8); if rhs1 == null { return null }
// then Return(Int A) // then Return(Int A)
local kth = s.indexOf("\"then\":", k_if1); if kth < 0 { return null } local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if1); if kth < 0 { return null }
local rt1 = s.indexOf("\"type\":\"Return\"", kth); if rt1 < 0 { return null } local rt1 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth); if rt1 < 0 { return null }
local ti13 = s.indexOf("\"type\":\"Int\"", rt1); if ti13 < 0 { return null } local ti13 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt1); if ti13 < 0 { return null }
local kv13 = s.indexOf("\"value\":", ti13); if kv13 < 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 } local aval = JsonFragBox.read_int_after(s, kv13 + 8); if aval == null { return null }
// else contains nested If with Return(Int)/Return(Int) // else contains nested If with Return(Int)/Return(Int)
local kel = s.indexOf("\"else\":", k_if1); if kel < 0 { return null } local kel = JsonFragBox.index_of_from(s, "\"else\":", k_if1); if kel < 0 { return null }
local k_if2 = s.indexOf("\"type\":\"If\"", kel); if k_if2 < 0 { return null } local k_if2 = JsonFragBox.index_of_from(s, "\"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 k_cmp2 = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", k_if2); if k_cmp2 < 0 { return null }
local kop2 = s.indexOf("\"op\":", k_cmp2); if kop2 < 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 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 op2 = PatternUtilBox.map_cmp(op2s); if op2 == null { return null }
local klhs2 = s.indexOf("\"lhs\":{", k_cmp2); if klhs2 < 0 { return null } local klhs2 = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp2); if klhs2 < 0 { return null }
local ti21 = s.indexOf("\"type\":\"Int\"", klhs2); if ti21 < 0 { return null } local ti21 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", klhs2); if ti21 < 0 { return null }
local kv21 = s.indexOf("\"value\":", ti21); if kv21 < 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 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 krhs2 = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp2); if krhs2 < 0 { return null }
local ti22 = s.indexOf("\"type\":\"Int\"", krhs2); if ti22 < 0 { return null } local ti22 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", krhs2); if ti22 < 0 { return null }
local kv22 = s.indexOf("\"value\":", ti22); if kv22 < 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 } local rhs2 = JsonFragBox.read_int_after(s, kv22 + 8); if rhs2 == null { return null }
// then Return(Int B) // then Return(Int B)
local kth2 = s.indexOf("\"then\":", k_if2); if kth2 < 0 { return null } local kth2 = JsonFragBox.index_of_from(s, "\"then\":", k_if2); if kth2 < 0 { return null }
local rt2 = s.indexOf("\"type\":\"Return\"", kth2); if rt2 < 0 { return null } local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth2); if rt2 < 0 { return null }
local ti23 = s.indexOf("\"type\":\"Int\"", rt2); if ti23 < 0 { return null } local ti23 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2); if ti23 < 0 { return null }
local kv23 = s.indexOf("\"value\":", ti23); if kv23 < 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 } local bval = JsonFragBox.read_int_after(s, kv23 + 8); if bval == null { return null }
// else Return(Int C) // else Return(Int C)
local kel2 = s.indexOf("\"else\":", k_if2); if kel2 < 0 { return null } local kel2 = JsonFragBox.index_of_from(s, "\"else\":", k_if2); if kel2 < 0 { return null }
local rt3 = s.indexOf("\"type\":\"Return\"", kel2); if rt3 < 0 { return null } local rt3 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kel2); if rt3 < 0 { return null }
local ti24 = s.indexOf("\"type\":\"Int\"", rt3); if ti24 < 0 { return null } local ti24 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt3); if ti24 < 0 { return null }
local kv24 = s.indexOf("\"value\":", ti24); if kv24 < 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 } local cval = JsonFragBox.read_int_after(s, kv24 + 8); if cval == null { return null }
// Build MIR(JSON) // Build MIR(JSON)

View File

@ -10,29 +10,29 @@ static box LowerIfThenElseFollowingReturnBox {
try_lower(program_json) { try_lower(program_json) {
local s = "" + program_json local s = "" + program_json
// If with Compare(Int,Int) // 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 } 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 } 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 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 } local op = PatternUtilBox.map_cmp(sym); if op == null { return null }
// LHS/RHS ints // LHS/RHS ints
local klhs = s.indexOf("\"lhs\":{", k_cmp); if klhs < 0 { return null } local klhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp); if klhs < 0 { return null }
local ti1 = s.indexOf("\"type\":\"Int\"", klhs); if ti1 < 0 { return null } local ti1 = JsonFragBox.index_of_from(s, "\"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 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 = s.indexOf("\"rhs\":{", k_cmp); if krhs < 0 { return null } local krhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp); if krhs < 0 { return null }
local ti2 = s.indexOf("\"type\":\"Int\"", krhs); if ti2 < 0 { return null } local ti2 = JsonFragBox.index_of_from(s, "\"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 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) // then: Return(Int)
local kth = s.indexOf("\"then\":", k_if); if kth < 0 { return null } local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if); if kth < 0 { return null }
local rt = s.indexOf("\"type\":\"Return\"", kth); if rt < 0 { return null } local rt = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth); if rt < 0 { return null }
local ti3 = s.indexOf("\"type\":\"Int\"", rt); if ti3 < 0 { return null } local ti3 = JsonFragBox.index_of_from(s, "\"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 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 // 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 k_after = JsonFragBox.index_of_from(s, "\"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 ti4 = JsonFragBox.index_of_from(s, "\"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 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) // Build MIR(JSON)
local b0 = new ArrayBox() local b0 = new ArrayBox()

View File

@ -12,27 +12,27 @@ static box LowerLoopCountParamBox {
local s = "" + program_json local s = "" + program_json
// Discover loop variable name from Compare first // Discover loop variable name from Compare first
// We'll accept either lhs Var(name) or rhs Var(name) // 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 } 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 } if k_cmp < 0 { return null }
local varname = LoopScanBox.find_loop_var_name(s, k_cmp) local varname = LoopScanBox.find_loop_var_name(s, k_cmp)
if varname == null { return null } if varname == null { return null }
// Local <varname> = (Int init | Var initName) // 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 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 init = null
{ {
local k_init_int = s.indexOf("\"type\":\"Int\"", k_local_i) local k_init_int = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_local_i)
local k_loop_next = s.indexOf("\"type\":\"Loop\"", 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) { 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 { } 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) { 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) local vname = JsonFragBox.read_string_after(s, kn_i)
if vname != null { init = PatternUtilBox.find_local_int_before(s, vname, k_local_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 } if init == null { return null }
// Loop Compare normalize: accept < / <= / > / >= with Var(varname) on either side // 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) // 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) local op = JsonFragBox.read_string_after(s, k_op + 5)
if op == null { return null } if op == null { return null }
local has_lhs_i = s.indexOf("\"lhs\":{\"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 = s.indexOf("\"rhs\":{\"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 } if !has_lhs_i && !has_rhs_i { return null }
local cmp = null local cmp = null
local limit = null local limit = null
if has_lhs_i { if has_lhs_i {
// rhs Int/Var → resolve limit // rhs Int/Var → resolve limit
local k_rhs = s.indexOf("\"rhs\":{", k_cmp); if k_rhs < 0 { return null } local k_rhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp); if k_rhs < 0 { return null }
local k_lim_t = s.indexOf("\"type\":\"Int\"", k_rhs) local k_lim_t = JsonFragBox.index_of_from(s, "\"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) } } 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 { else {
local k_rv = s.indexOf("\"type\":\"Var\"", k_rhs); if k_rv < 0 { return null } local k_rv = JsonFragBox.index_of_from(s, "\"type\":\"Var\"", k_rhs); if k_rv < 0 { return null }
local kn = s.indexOf("\"name\":\"", k_rhs); if kn < 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 } local lname = JsonFragBox.read_string_after(s, kn); if lname == null { return null }
limit = PatternUtilBox.find_local_int_before(s, lname, k_cmp) limit = PatternUtilBox.find_local_int_before(s, lname, k_cmp)
} }
@ -69,12 +69,12 @@ static box LowerLoopCountParamBox {
limit = norm.substring(cpos+1, norm.length()) limit = norm.substring(cpos+1, norm.length())
} else { } else {
if op != ">" && op != ">=" && op != "<" && op != "<=" && op != "!=" { return null } if op != ">" && op != ">=" && op != "<" && op != "<=" && op != "!=" { return null }
local k_lhs = s.indexOf("\"lhs\":{", k_cmp); if k_lhs < 0 { return null } local k_lhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp); if k_lhs < 0 { return null }
local k_lim_t2 = s.indexOf("\"type\":\"Int\"", k_lhs) local k_lim_t2 = JsonFragBox.index_of_from(s, "\"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) } } 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 { else {
local k_lv = s.indexOf("\"type\":\"Var\"", k_lhs); if k_lv < 0 { return null } local k_lv = JsonFragBox.index_of_from(s, "\"type\":\"Var\"", k_lhs); if k_lv < 0 { return null }
local kn3 = s.indexOf("\"name\":\"", k_lhs); if kn3 < 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 } local lname3 = JsonFragBox.read_string_after(s, kn3); if lname3 == null { return null }
limit = PatternUtilBox.find_local_int_before(s, lname3, k_cmp) limit = PatternUtilBox.find_local_int_before(s, lname3, k_cmp)
} }
@ -86,27 +86,27 @@ static box LowerLoopCountParamBox {
limit = norm2.substring(cpos2+1, norm2.length()) limit = norm2.substring(cpos2+1, norm2.length())
} }
// Body increment: Local i = Binary('+', Var i, Int step) // 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 } 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 } if k_bop < 0 { return null }
// Body increment: Local i = Binary(op '+' or '-', Var i, (Int step | Var stepName)) // Body increment: Local i = Binary(op '+' or '-', Var i, (Int step | Var stepName))
local bop_plus = (s.indexOf("\"op\":\"+\"", k_bop) >= 0) local bop_plus = (JsonFragBox.index_of_from(s, "\"op\":\"+\"", k_bop) >= 0)
local bop_minus = (s.indexOf("\"op\":\"-\"", k_bop) >= 0) local bop_minus = (JsonFragBox.index_of_from(s, "\"op\":\"-\"", k_bop) >= 0)
if (!bop_plus && !bop_minus) { return null } 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 local step = null
// Prefer rhs Int if present; otherwise try rhs Var and reverse-lookup its Local Int // 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_rhsb = JsonFragBox.index_of_from(s, "\"rhs\":{", k_bop); if k_rhsb < 0 { return null }
local k_t_int = s.indexOf("\"type\":\"Int\"", k_rhsb) local k_t_int = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhsb)
if k_t_int >= 0 { 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 { } 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 } 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 } local vname = JsonFragBox.read_string_after(s, kns); if vname == null { return null }
step = PatternUtilBox.find_local_int_before(s, vname, k_bop) step = PatternUtilBox.find_local_int_before(s, vname, k_bop)
} }

View File

@ -12,38 +12,38 @@ static box LowerLoopSimpleBox {
try_lower(program_json) { try_lower(program_json) {
local s = "" + program_json local s = "" + program_json
// Find Loop with cond Compare and normalize to canonical (<) with dynamic var name // 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 } 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 } if k_cmp < 0 { return null }
// discover loop var name from cond (lhs or rhs Var) // discover loop var name from cond (lhs or rhs Var)
local varname = LoopScanBox.find_loop_var_name(s, k_cmp) local varname = LoopScanBox.find_loop_var_name(s, k_cmp)
if varname == null { return null } if varname == null { return null }
// op: accept '<' / '<=' as-is, '!=' (with var on lhs) as '<', and swapped '>' / '>=' (with var on rhs) // 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) local op = JsonFragBox.read_string_after(s, k_op + 5)
if op == null { return null } if op == null { return null }
// Determine where Var(varname) is and extract the Int from the opposite side // 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_lhs_i = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0
local has_rhs_i = s.indexOf("\"rhs\":{\"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 } if !has_lhs_i && !has_rhs_i { return null }
local swapped = 0 local swapped = 0
local limit = null local limit = null
if has_lhs_i { if has_lhs_i {
// rhs Int value // rhs Int value
local k_rhs = s.indexOf("\"rhs\":{", k_cmp); if k_rhs < 0 { return null } local k_rhs = JsonFragBox.index_of_from(s, "\"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_ti = JsonFragBox.index_of_from(s, "\"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_v = JsonFragBox.index_of_from(s, "\"value\":", k_ti); if k_v < 0 { return null }
limit = JsonFragBox.read_int_after(s, k_v + 8) limit = JsonFragBox.read_int_after(s, k_v + 8)
if limit == null { return null } if limit == null { return null }
} else { } else {
// Var is on rhs; lhs must be Int // Var is on rhs; lhs must be Int
swapped = 1 swapped = 1
local k_lhs = s.indexOf("\"lhs\":{", k_cmp); if k_lhs < 0 { return null } local k_lhs = JsonFragBox.index_of_from(s, "\"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_ti2 = JsonFragBox.index_of_from(s, "\"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_v2 = JsonFragBox.index_of_from(s, "\"value\":", k_ti2); if k_v2 < 0 { return null }
limit = JsonFragBox.read_int_after(s, k_v2 + 8) limit = JsonFragBox.read_int_after(s, k_v2 + 8)
if limit == null { return null } if limit == null { return null }
} }

View File

@ -21,19 +21,19 @@ static box LowerLoopSumBcBox {
print("[sum_bc] enter lower") print("[sum_bc] enter lower")
} }
// Loop and Compare normalize to canonical (<) with dynamic var name // 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 } 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 } if k_cmp < 0 { return null }
// discover loop var name from cond (lhs or rhs Var) // discover loop var name from cond (lhs or rhs Var)
local varname = null local varname = null
{ {
local kl = s.indexOf("\"lhs\":{", k_cmp); local kr = s.indexOf("\"rhs\":{", k_cmp) local kl = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp); local kr = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp)
if kl >= 0 && s.indexOf("\"type\":\"Var\"", kl) >= 0 { if kl >= 0 && JsonFragBox.index_of_from(s, "\"type\":\"Var\"", kl) >= 0 {
local kn = s.indexOf("\"name\":\"", kl); if kn >= 0 { varname = JsonFragBox.read_string_after(s, kn) } 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 { if varname == null && kr >= 0 && JsonFragBox.index_of_from(s, "\"type\":\"Var\"", kr) >= 0 {
local kn2 = s.indexOf("\"name\":\"", kr); if kn2 >= 0 { varname = JsonFragBox.read_string_after(s, kn2) } local kn2 = JsonFragBox.index_of_from(s, "\"name\":\"", kr); if kn2 >= 0 { varname = JsonFragBox.read_string_after(s, kn2) }
} }
} }
if varname == null { return null } if varname == null { return null }
@ -41,27 +41,27 @@ static box LowerLoopSumBcBox {
print("[sum_bc] var=" + varname) print("[sum_bc] var=" + varname)
} }
// op: accept '<'/'<=' with var on lhs; also accept swapped '>'/'>=' with var on rhs // 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) local op = JsonFragBox.read_string_after(s, k_op + 5)
if op == null { return null } if op == null { return null }
local has_lhs_i = s.indexOf("\"lhs\":{\"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 = s.indexOf("\"rhs\":{\"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 } if !has_lhs_i && !has_rhs_i { return null }
local limit = null local limit = null
if has_lhs_i { if has_lhs_i {
if op != "<" && op != "<=" { return null } if op != "<" && op != "<=" { return null }
// rhs Int limit // rhs Int limit
local k_rhs = s.indexOf("\"rhs\":{", k_cmp); if k_rhs < 0 { return null } local k_rhs = JsonFragBox.index_of_from(s, "\"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_ti = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhs); if k_ti < 0 { return null }
local kv = s.indexOf("\"value\":", k_ti); if kv < 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 } 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) } if op == "<=" { limit = StringHelpers.int_to_str(JsonFragBox._str_to_int(limit) + 1) }
} else { } else {
// swapped: Int on lhs, Var i on rhs, op should be '>' or '>=' // swapped: Int on lhs, Var i on rhs, op should be '>' or '>='
if op != ">" && op != ">=" { return null } if op != ">" && op != ">=" { return null }
local k_lhs = s.indexOf("\"lhs\":{", k_cmp); if k_lhs < 0 { return null } local k_lhs = JsonFragBox.index_of_from(s, "\"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_ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhs); if k_ti2 < 0 { return null }
local kv2 = s.indexOf("\"value\":", k_ti2); if kv2 < 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 } 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) } 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 // Break sentinel: If(cond Compare var==X or X==var) then Break
local break_value = null 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 { if kb >= 0 {
// Find nearest previous Compare and grab rhs Int // Find nearest previous Compare and grab rhs Int
local kbc = s.lastIndexOf("\"type\":\"Compare\"", kb) local kbc = s.lastIndexOf("\"type\":\"Compare\"", kb)
if kbc >= 0 { if kbc >= 0 {
// Ensure op=="==" and lhs Var i // 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 == "==" { if bop != null && bop == "==" {
local lhs_i = s.indexOf("\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kbc) >= 0 local lhs_i = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kbc) >= 0
local rhs_i = s.indexOf("\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kbc) >= 0 local rhs_i = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kbc) >= 0
if lhs_i { if lhs_i {
local kbi = s.indexOf("\"type\":\"Int\"", s.indexOf("\"rhs\":{", kbc)) local k_rhsb = JsonFragBox.index_of_from(s, "\"rhs\":{", kbc)
if kbi >= 0 { local kvb = s.indexOf("\"value\":", kbi); if kvb >= 0 { break_value = JsonFragBox.read_int_after(s, kvb + 8) } } 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 { } else if rhs_i {
local kbi2 = s.indexOf("\"type\":\"Int\"", s.indexOf("\"lhs\":{", kbc)) local k_lhsb = JsonFragBox.index_of_from(s, "\"lhs\":{", kbc)
if kbi2 >= 0 { local kvb2 = s.indexOf("\"value\":", kbi2); if kvb2 >= 0 { break_value = JsonFragBox.read_int_after(s, kvb2 + 8) } } 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 == "!=" { } else if bop != null && bop == "!=" {
// Delegate to loop-scan helper for '!=' + else [Break] // Delegate to loop-scan helper for '!=' + else [Break]
@ -92,11 +94,11 @@ static box LowerLoopSumBcBox {
// Fallback: try local JsonFragBox-based extraction near kbc // Fallback: try local JsonFragBox-based extraction near kbc
if break_value == null { if break_value == null {
// Read Int from lhs or rhs around kbc // Read Int from lhs or rhs around kbc
local k_rhsb = s.indexOf("\"rhs\":{", kbc); local k_lhsb = s.indexOf("\"lhs\":{", kbc) local k_rhsb = JsonFragBox.index_of_from(s, "\"rhs\":{", kbc); local k_lhsb = JsonFragBox.index_of_from(s, "\"lhs\":{", kbc)
if k_rhsb >= 0 && s.indexOf("\"type\":\"Int\"", k_rhsb) >= 0 { if k_rhsb >= 0 && JsonFragBox.index_of_from(s, "\"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) } 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 && s.indexOf("\"type\":\"Int\"", k_lhsb) >= 0 { } else if k_lhsb >= 0 && JsonFragBox.index_of_from(s, "\"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 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 // Continue sentinel: If(cond Compare var==Y or Y==var) then Continue
local skip_value = null 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 { if kc >= 0 {
local kcc = s.lastIndexOf("\"type\":\"Compare\"", kc) local kcc = s.lastIndexOf("\"type\":\"Compare\"", kc)
if kcc >= 0 { 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 == "==" { if cop != null && cop == "==" {
local lhs_i2 = s.indexOf("\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kcc) >= 0 local lhs_i2 = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kcc) >= 0
local rhs_i2 = s.indexOf("\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kcc) >= 0 local rhs_i2 = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kcc) >= 0
if lhs_i2 { if lhs_i2 {
local kci = s.indexOf("\"type\":\"Int\"", s.indexOf("\"rhs\":{", kcc)) local k_rhsb2 = JsonFragBox.index_of_from(s, "\"rhs\":{", kcc)
if kci >= 0 { local kvs = s.indexOf("\"value\":", kci); if kvs >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs + 8) } } 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 { } else if rhs_i2 {
local kci2 = s.indexOf("\"type\":\"Int\"", s.indexOf("\"lhs\":{", kcc)) local k_lhsb2 = JsonFragBox.index_of_from(s, "\"lhs\":{", kcc)
if kci2 >= 0 { local kvs2 = s.indexOf("\"value\":", kci2); if kvs2 >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs2 + 8) } } 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 == "!=" { } else if cop != null && cop == "!=" {
// Delegate to loop-scan helper for '!=' + else [Continue] // 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) } if skip_value == null { skip_value = LoopScanBox.extract_ne_else_sentinel_value(s, "Continue", k_loop, varname) }
// Fallback: JsonFragBox-based local extraction near kcc // Fallback: JsonFragBox-based local extraction near kcc
if skip_value == null { if skip_value == null {
local k_rhsb2 = s.indexOf("\"rhs\":{", kcc); local k_lhsb2 = s.indexOf("\"lhs\":{", kcc) local k_rhsb2x = JsonFragBox.index_of_from(s, "\"rhs\":{", kcc); local k_lhsb2x = JsonFragBox.index_of_from(s, "\"lhs\":{", kcc)
if k_rhsb2 >= 0 && s.indexOf("\"type\":\"Int\"", k_rhsb2) >= 0 { if k_rhsb2x >= 0 && JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhsb2x) >= 0 {
local kvs = s.indexOf("\"value\":", s.indexOf("\"type\":\"Int\"", k_rhsb2)); if kvs >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs + 8) } 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_lhsb2 >= 0 && s.indexOf("\"type\":\"Int\"", k_lhsb2) >= 0 { } else if k_lhsb2x >= 0 && JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhsb2x) >= 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 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) { try_lower(program_json) {
if program_json == null { return null } if program_json == null { return null }
local s = "" + program_json local s = "" + program_json
if s.indexOf("\"type\":\"New\"") < 0 { return null } if JsonFragBox.index_of_from(s, "\"type\":\"New\"", 0) < 0 { return null }
if s.indexOf("\"class\":\"ArrayBox\"") < 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 // Reverse-lookup (safe subset): prefer Local(Int) for index, Local(String) for value
local n = s.length() local n = s.length()
local idx = PatternUtilBox.find_any_local_int_before(s, n) local idx = PatternUtilBox.find_any_local_int_before(s, n)

View File

@ -5,8 +5,8 @@ static box LowerMethodArrayPushBox {
try_lower(program_json) { try_lower(program_json) {
if program_json == null { return null } if program_json == null { return null }
local s = "" + program_json local s = "" + program_json
if s.indexOf("\"type\":\"New\"") < 0 { return null } if JsonFragBox.index_of_from(s, "\"type\":\"New\"", 0) < 0 { return null }
if s.indexOf("\"class\":\"ArrayBox\"") < 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 // Reverse-lookup (safe subset): prefer Local(Int) for push values when present
local n = s.length() local n = s.length()
local p1 = PatternUtilBox.find_any_local_int_before(s, n); if p1 == null { p1 = "1" } 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) { try_lower(program_json) {
if program_json == null { return null } if program_json == null { return null }
local s = "" + program_json local s = "" + program_json
if s.indexOf("\"type\":\"New\"") < 0 { return null } if JsonFragBox.index_of_from(s, "\"type\":\"New\"", 0) < 0 { return null }
if s.indexOf("\"class\":\"ArrayBox\"") < 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 // 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\":[" + 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\":[]}}," + "{\"op\":\"mir_call\",\"dst\":1,\"mir_call\":{\"callee\":{\"type\":\"Constructor\",\"box_type\":\"ArrayBox\"},\"args\":[],\"effects\":[]}}," +
@ -16,4 +16,3 @@ static box LowerMethodArraySizeBox {
return json return json
} }
} }

View File

@ -5,8 +5,8 @@ static box LowerMethodMapGetSetBox {
try_lower(program_json) { try_lower(program_json) {
if program_json == null { return null } if program_json == null { return null }
local s = "" + program_json local s = "" + program_json
if s.indexOf("\"type\":\"New\"") < 0 { return null } if JsonFragBox.index_of_from(s, "\"type\":\"New\"", 0) < 0 { return null }
if s.indexOf("\"class\":\"MapBox\"") < 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 // Reverse-lookup (safe subset): prefer Local(String) for key, Local(Int) for value
local n = s.length() local n = s.length()
local key = PatternUtilBox.find_any_local_string_before(s, n) local key = PatternUtilBox.find_any_local_string_before(s, n)

View File

@ -4,8 +4,8 @@ static box LowerMethodMapSizeBox {
try_lower(program_json) { try_lower(program_json) {
if program_json == null { return null } if program_json == null { return null }
local s = "" + program_json local s = "" + program_json
if s.indexOf("\"type\":\"New\"") < 0 { return null } if JsonFragBox.index_of_from(s, "\"type\":\"New\"", 0) < 0 { return null }
if s.indexOf("\"class\":\"MapBox\"") < 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\":[" + 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\":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\":[]}}," + "{\"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 return json
} }
} }

View File

@ -7,11 +7,11 @@ static box LowerNewboxConstructorBox {
if program_json == null { return null } if program_json == null { return null }
local s = "" + program_json local s = "" + program_json
// Quick pattern check // 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) // Find class name (minimal scan)
local cls = null local cls = null
if s.indexOf("\"class\":\"ArrayBox\"") >= 0 { cls = "ArrayBox" } if JsonFragBox.index_of_from(s, "\"class\":\"ArrayBox\"", 0) >= 0 { cls = "ArrayBox" }
else { if s.indexOf("\"class\":\"MapBox\"") >= 0 { cls = "MapBox" } } else { if JsonFragBox.index_of_from(s, "\"class\":\"MapBox\"", 0) >= 0 { cls = "MapBox" } }
if cls == null { return null } if cls == null { return null }
// Only accept known minimal boxes // Only accept known minimal boxes
if !(cls == "ArrayBox" || cls == "MapBox") { return null } 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 { static box LowerReturnBinOpBox {
try_lower(program_json) { try_lower(program_json) {
local s = "" + 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 } 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 } if k_bin < 0 { return null }
// op // 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 } if k_op < 0 { return null }
local op = JsonFragBox.read_string_after(s, k_op + 5) local op = JsonFragBox.read_string_after(s, k_op + 5)
if op == null { return null } if op == null { return null }
if !(op == "+" || op == "-" || op == "*" || op == "/") { return null } if !(op == "+" || op == "-" || op == "*" || op == "/") { return null }
// lhs/rhs object starts // lhs/rhs object starts
local klhs = s.indexOf("\"lhs\":{", k_bin) local klhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_bin)
local krhs = s.indexOf("\"rhs\":{", k_bin) local krhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_bin)
if klhs < 0 { return null } if klhs < 0 { return null }
// strictly ensure lhs node is Int by bounding search before rhs start // 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 ti < 0 { return null }
if krhs >= 0 && ti >= krhs { 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 kv_lhs < 0 { return null }
if krhs >= 0 && kv_lhs >= krhs { return null } if krhs >= 0 && kv_lhs >= krhs { return null }
local lhs_val = JsonFragBox.read_int_after(s, kv_lhs + 8) local lhs_val = JsonFragBox.read_int_after(s, kv_lhs + 8)
if lhs_val == null { return null } if lhs_val == null { return null }
// rhs int // rhs int
if krhs < 0 { return null } 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 } 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 } if kv_rhs < 0 { return null }
local rhs_val = JsonFragBox.read_int_after(s, kv_rhs + 8) local rhs_val = JsonFragBox.read_int_after(s, kv_rhs + 8)
if rhs_val == null { return null } if rhs_val == null { return null }

View File

@ -10,26 +10,27 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox
static box LowerReturnBinOpVarIntBox { static box LowerReturnBinOpVarIntBox {
try_lower(program_json) { try_lower(program_json) {
local s = "" + 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 } 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 } 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 } if k_op < 0 { return null }
local op = JsonFragBox.read_string_after(s, k_op + 5) local op = JsonFragBox.read_string_after(s, k_op + 5)
if op == null { return null } 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 // Try Var + Int
local klhs_var = s.indexOf("\"lhs\":{\"type\":\"Var\"", k_bin) local klhs_var = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\"", k_bin)
local krhs_int = s.indexOf("\"rhs\":{\"type\":\"Int\"", k_bin) local krhs_int = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Int\"", k_bin)
local var_name = null local var_name = null
local rhs_val = null local rhs_val = null
if klhs_var >= 0 && krhs_int >= 0 { 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) 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 { 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) rhs_val = JsonFragBox.read_int_after(s, kv + 8)
} }
if var_name != null && rhs_val != null { if var_name != null && rhs_val != null {
@ -38,7 +39,7 @@ static box LowerReturnBinOpVarIntBox {
local b0 = new ArrayBox() local b0 = new ArrayBox()
b0.push(MirSchemaBox.inst_const(1, var_val)) b0.push(MirSchemaBox.inst_const(1, var_val))
b0.push(MirSchemaBox.inst_const(2, rhs_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)) b0.push(MirSchemaBox.inst_ret(3))
local blocks = new ArrayBox(); blocks.push(MirSchemaBox.block(0, b0)) local blocks = new ArrayBox(); blocks.push(MirSchemaBox.block(0, b0))
return MirSchemaBox.module(MirSchemaBox.fn_main(blocks)) return MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
@ -46,17 +47,17 @@ static box LowerReturnBinOpVarIntBox {
} }
} }
// Try Int + Var // Try Int + Var
local klhs_int = s.indexOf("\"lhs\":{\"type\":\"Int\"", k_bin) local klhs_int = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Int\"", k_bin)
local krhs_var = s.indexOf("\"rhs\":{\"type\":\"Var\"", k_bin) local krhs_var = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\"", k_bin)
var_name = null var_name = null
local lhs_val = null local lhs_val = null
if klhs_int >= 0 && krhs_var >= 0 { 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 { 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) 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) var_name = JsonFragBox.read_string_after(s, k_name2 + 7)
if lhs_val != null && var_name != null { if lhs_val != null && var_name != null {
local var_val2 = PatternUtilBox.find_local_int_before(s, var_name, k_ret) local var_val2 = PatternUtilBox.find_local_int_before(s, var_name, k_ret)
@ -64,7 +65,7 @@ static box LowerReturnBinOpVarIntBox {
local b1 = new ArrayBox() local b1 = new ArrayBox()
b1.push(MirSchemaBox.inst_const(1, lhs_val)) b1.push(MirSchemaBox.inst_const(1, lhs_val))
b1.push(MirSchemaBox.inst_const(2, var_val2)) 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)) b1.push(MirSchemaBox.inst_ret(3))
local blocks = new ArrayBox(); blocks.push(MirSchemaBox.block(0, b1)) local blocks = new ArrayBox(); blocks.push(MirSchemaBox.block(0, b1))
return MirSchemaBox.module(MirSchemaBox.fn_main(blocks)) 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 { static box LowerReturnBinOpVarVarBox {
try_lower(program_json){ try_lower(program_json){
local s = "" + program_json local s = "" + program_json
local k_ret = s.indexOf("\"type\":\"Return\""); if k_ret < 0 { return null } 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); if k_bin < 0 { return null } 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); if k_op < 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 } local op = JsonFragBox.read_string_after(s, k_op + 5); if op == null { return null }
if !(op == "+" || op == "-" || op == "*" || op == "/") { return null } local kind = PatternUtilBox.map_binop(op); if kind == null { return null }
local klhs = s.indexOf("\"lhs\":{\"type\":\"Var\"", k_bin); if klhs < 0 { return null } local klhs = JsonFragBox.index_of_from(s, "\"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 krhs = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\"", k_bin); if krhs < 0 { return null }
local knl = s.indexOf("\"name\":", klhs); if knl < 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 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 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 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 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)); local blocks=new ArrayBox(); blocks.push(MirSchemaBox.block(0,b0));
return MirSchemaBox.module(MirSchemaBox.fn_main(blocks)) 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 { static box LowerReturnBoolBox {
try_lower(program_json) { try_lower(program_json) {
local s = "" + 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 } if k_ret < 0 { return null }
// Restrict to Return(expr=Bool …): require expr 開始直後に Bool が来る // Restrict to Return(expr=Bool …): require expr 開始直後に Bool が来る
// 例: "expr":{"type":"Bool","value":true} // 例: "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 } 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 } if k_bool < 0 { return null }
// Ensure this Bool belongs to the same expr (次の '}' までに value があることを確認) // 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 } if k_val < 0 { return null }
local is_true = JsonFragBox.read_bool_after(s, k_val+8) local is_true = JsonFragBox.read_bool_after(s, k_val+8)
if is_true == null { return null } if is_true == null { return null }

View File

@ -6,11 +6,11 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox
static box LowerReturnFloatBox { static box LowerReturnFloatBox {
try_lower(program_json) { try_lower(program_json) {
local s = "" + 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 } 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 } 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 } if k_val < 0 { return null }
local fstr = JsonFragBox.read_float_after(s, k_val+8) local fstr = JsonFragBox.read_float_after(s, k_val+8)
if fstr == null { return null } if fstr == null { return null }

View File

@ -5,14 +5,14 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox
static box LowerReturnIntBox { static box LowerReturnIntBox {
try_lower(program_json) { try_lower(program_json) {
local s = "" + 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 } if k_ret < 0 { return null }
// Find expr object // 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 } if k_expr < 0 { return null }
// Check that expr.type is directly Int (not Binary, Logical, Var, etc) // Check that expr.type is directly Int (not Binary, Logical, Var, etc)
local k_type_start = k_expr + 8 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 } if k_type < 0 || k_type > k_type_start + 20 { return null }
// Extract type value to verify it's "Int" // Extract type value to verify it's "Int"
local k_type_val = k_type + 7 local k_type_val = k_type + 7
@ -28,9 +28,9 @@ static box LowerReturnIntBox {
if k_type_val + 3 >= n { return null } if k_type_val + 3 >= n { return null }
if s.substring(k_type_val+3, k_type_val+4) != "\"" { return null } if s.substring(k_type_val+3, k_type_val+4) != "\"" { return null }
// Now extract the value // 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 } 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) local val = JsonFragBox.read_int_after(s, kv + 8)
if val == null { return null } if val == null { return null }
local debug_on = 0 local debug_on = 0

View File

@ -11,7 +11,7 @@ static box LowerReturnLogicalBox {
try_lower(program_json) { try_lower(program_json) {
local s = "" + 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 } if k_ret < 0 { return null }
local k_log = JsonFragBox.index_of_from(s, "\"type\":\"Logical\"", k_ret) local k_log = JsonFragBox.index_of_from(s, "\"type\":\"Logical\"", k_ret)
if k_log < 0 { return null } if k_log < 0 { return null }

View File

@ -8,12 +8,12 @@ using selfhost.vm.helpers.method_alias_policy as MethodAliasPolicy
static box LowerReturnMethodArrayMapBox { static box LowerReturnMethodArrayMapBox {
try_lower(program_json) { try_lower(program_json) {
local s = "" + program_json local s = "" + program_json
local k_ret = s.indexOf("\"type\":\"Return\""); if k_ret < 0 { return null } local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0); if k_ret < 0 { return null }
local k_m = s.indexOf("\"type\":\"Method\"", k_ret); if k_m < 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) // 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 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) // Standardize: generate 'size' (len/length are accepted aliases at receiver)
method = MethodAliasPolicy.normalize_size(method) method = MethodAliasPolicy.normalize_size(method)
// Allow basic methods // Allow basic methods
@ -23,91 +23,56 @@ static box LowerReturnMethodArrayMapBox {
local b0 = new ArrayBox() local b0 = new ArrayBox()
// Receiver placeholder (Var resolve未実装のため 0 を置く) // Receiver placeholder (Var resolve未実装のため 0 を置く)
b0.push(MirSchemaBox.inst_const(1, 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 local next_id = 2
if k_args >= 0 { if k_args >= 0 {
// first arg: Int or Var(Int) // first arg: Int or Var(Int)
local k_i1 = s.indexOf("\"type\":\"Int\"", k_args) local k_i1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_args)
local k_v1 = s.indexOf("\"type\":\"Var\"", 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) { if k_i1 >= 0 && (k_v1 < 0 || k_i1 < k_v1) {
// read numeric after value: // 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 { if k_val1 >= 0 {
local v1 = JsonFragBox.read_int_after(s, k_val1 + 8) local v1 = JsonFragBox.read_int_after(s, k_val1 + 8)
if v1 != null { b0.push(MirSchemaBox.inst_const(next_id, v1)) args_ids.push(next_id) next_id = next_id + 1 } if v1 != null { b0.push(MirSchemaBox.inst_const(next_id, v1)) args_ids.push(next_id) next_id = next_id + 1 }
} }
// second arg after first // second arg after first
local k_i2 = s.indexOf("\"type\":\"Int\"", k_i1 + 1) local k_i2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_i1 + 1)
local k_v2a = s.indexOf("\"type\":\"Var\"", k_i1 + 1) local k_v2a = JsonFragBox.index_of_from(s, "\"type\":\"Var\"", k_i1 + 1)
if k_i2 >= 0 { 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 } } 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 { } else if k_v2a >= 0 {
// second arg is Var: resolve Local Int value // 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 { if kn >= 0 {
local name2 = JsonFragBox.read_string_after(s, kn) local name2 = JsonFragBox.read_string_after(s, kn)
// scan backwards for Local name2 Int local v = PatternUtilBox.find_local_int_before(s, name2, k_m)
local pos = 0; local last = -1 if v != null { b0.push(MirSchemaBox.inst_const(next_id, v)) args_ids.push(next_id) next_id = next_id + 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 } }
}
}
} }
} }
} else if k_v1 >= 0 && (k_i1 < 0 || k_v1 < k_i1) { } else if k_v1 >= 0 && (k_i1 < 0 || k_v1 < k_i1) {
// first arg is Var: resolve Local value (Int/Bool/Float/String) // 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 { if kn >= 0 {
local namev = JsonFragBox.read_string_after(s, kn) local namev = JsonFragBox.read_string_after(s, kn)
// find last Local namev Int before method // Prefer exact-name Local lookups via PatternUtilBox
local pos2 = 0; local last2 = -1 // Int / Bool / Float / String (in this order)
loop(true) {
local kL2 = s.indexOf("\"type\":\"Local\"", pos2)
if kL2 < 0 || kL2 >= k_m { break }
local nm2 = null
{ {
local knm = s.indexOf("\"name\":\"", kL2) local vi = PatternUtilBox.find_local_int_before(s, namev, k_m)
if knm >= 0 { if vi != null { b0.push(MirSchemaBox.inst_const(next_id, vi)) args_ids.push(next_id) next_id = next_id + 1 }
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 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 vs = PatternUtilBox.find_local_string_before(s, namev, k_m)
local ki3 = s.indexOf("\"type\":\"Int\"", last2) if vs != null { b0.push(MirSchemaBox.inst_const_str(next_id, vs)) args_ids.push(next_id) next_id = next_id + 1 }
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 } } }
} }
} }
} }

View File

@ -6,11 +6,11 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox
static box LowerReturnStringBox { static box LowerReturnStringBox {
try_lower(program_json) { try_lower(program_json) {
local s = "" + 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 } 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 } 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 } if k_val < 0 { return null }
local sval = JsonFragBox.read_string_after(s, k_val+8) local sval = JsonFragBox.read_string_after(s, k_val+8)
if sval == null { return null } if sval == null { return null }

View File

@ -7,25 +7,25 @@ static box LowerReturnVarLocalBox {
try_lower(program_json) { try_lower(program_json) {
local s = "" + program_json local s = "" + program_json
// Find Local with name:"x" and expr Int value // 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 } if k_loc < 0 { return null }
// Extract name // 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) local name = JsonFragBox.read_string_after(s, k_name + 5)
if name == null || name == "" { return null } if name == null || name == "" { return null }
// Ensure expr Int after this Local // 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 } 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) local val = JsonFragBox.read_int_after(s, kv + 8)
if val == null { return null } if val == null { return null }
// Following Return Var(name) // 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 } if k_ret < 0 { return null }
// Verify Var(name) // 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 } 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) local vname = JsonFragBox.read_string_after(s, k_vn + 5)
if vname == null || vname != name { return null } if vname == null || vname != name { return null }

View File

@ -5,6 +5,7 @@ using selfhost.shared.common.string_helpers as StringHelpers
static box PatternUtilBox { 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_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} // Normalize (op, swapped, limit) → (cmp, limit') where cmp in {Lt, Le, Gt, Ge}
// swapped=0: i ? L, swapped=1: L ? i // swapped=0: i ? L, swapped=1: L ? i
normalize_cmp_limit(op, swapped, limit_str) { 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 // Bound the search between this Local and the next Local/before_pos
local next = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last + 1) local next = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last + 1)
if next < 0 || next > before_pos { next = before_pos } 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 } 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 } if kv < 0 || kv >= next { return null }
return JsonFragBox.read_int_after(s, kv+8) return JsonFragBox.read_int_after(s, kv+8)
} }
@ -62,14 +63,64 @@ static box PatternUtilBox {
if last<0 { return null } if last<0 { return null }
local next = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last + 1) local next = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last + 1)
if next < 0 || next > before_pos { next = before_pos } 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 } 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 } if kv < 0 || kv >= next { return null }
// JSON v0 uses 0/1 for bool values, not true/false literals // JSON v0 uses 0/1 for bool values, not true/false literals
return JsonFragBox.read_int_after(s, kv+8) 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). // Find the last Local(Int) before a given position (name-agnostic).
// Returns string digits or null when not found. // Returns string digits or null when not found.
find_any_local_int_before(s, before_pos) { find_any_local_int_before(s, before_pos) {

View File

@ -33,9 +33,12 @@ impl NyashEnv {
// Global current env config (thread-safe) // Global current env config (thread-safe)
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use std::collections::HashSet;
use std::sync::Mutex;
use std::sync::RwLock; use std::sync::RwLock;
static GLOBAL_ENV: OnceCell<RwLock<NyashEnv>> = OnceCell::new(); 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簡略化により不要 // フェーズM.2: PHI_ON_GATED_WARNED削除phi-legacy簡略化により不要
pub fn current() -> NyashEnv { pub fn current() -> NyashEnv {
@ -376,11 +379,19 @@ pub fn cli_verbose() -> bool {
} }
pub fn enable_using() -> bool { pub fn enable_using() -> bool {
// Phase 15: デフォルトONusing systemはメイン機能 // 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() { match std::env::var("NYASH_ENABLE_USING").ok().as_deref() {
Some("0") | Some("false") | Some("off") => false, Some("0") | Some("false") | Some("off") => return false,
_ => true, // デフォルト: ON 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) ---- // ---- 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). /// When enabled, the Rust parser accepts Stage-3 surface (try/catch/finally, throw).
/// Default is OFF to keep Stage-2 stable. /// Default is OFF to keep Stage-2 stable.
pub fn parser_stage3() -> bool { 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 /// Parser gate for BlockPostfix Catch acceptance
@ -578,3 +596,72 @@ pub fn oob_strict_fail() -> bool {
.or_else(|| env_flag("NYASH_OOB_STRICT_FAIL")) .or_else(|| env_flag("NYASH_OOB_STRICT_FAIL"))
.unwrap_or(false) .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 # Determine function signature
if name == "ny_main": if name == "ny_main":
# Special case: ny_main returns i32 # Special case: ny_main returns i64 to match runtime (nyrt) expectations
func_ty = ir.FunctionType(builder.i32, []) func_ty = ir.FunctionType(builder.i64, [])
else: else:
# Default: i64(i64, ...) signature; derive arity from '/N' suffix when params missing # Default: i64(i64, ...) signature; derive arity from '/N' suffix when params missing
m = re.search(r"/(\d+)$", name) m = re.search(r"/(\d+)$", name)

View File

@ -45,6 +45,22 @@ def lower_binop(
lhs_val = ir.Constant(ir.IntType(64), 0) lhs_val = ir.Constant(ir.IntType(64), 0)
if rhs_val is None: if rhs_val is None:
rhs_val = ir.Constant(ir.IntType(64), 0) 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 # Relational/equality operators delegate to compare
if op in ('==','!=','<','>','<=','>='): if op in ('==','!=','<','>','<=','>='):

View File

@ -97,9 +97,16 @@ def lower_return(
# Pointer type - null # Pointer type - null
ret_val = ir.Constant(return_type, None) 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: 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): 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' # Derive current block id from name like 'bb3'
cur_bid = None cur_bid = None

View File

@ -152,7 +152,8 @@ class NyashLLVMBuilder:
else: else:
arity = int(m.group(1)) if m else len(params_list) arity = int(m.group(1)) if m else len(params_list)
if name == "ny_main": if name == "ny_main":
fty = ir.FunctionType(self.i32, []) # Align with runtime expectation: ny_main returns i64
fty = ir.FunctionType(self.i64, [])
else: else:
fty = ir.FunctionType(self.i64, [self.i64] * arity) fty = ir.FunctionType(self.i64, [self.i64] * arity)
exists = False exists = False

View File

@ -13,8 +13,7 @@ fn main() {
// If NYASH_VERIFY_JSON is present and route is requested, execute and exit. // If NYASH_VERIFY_JSON is present and route is requested, execute and exit.
// This avoids plugin host/registry initialization and keeps output minimal. // This avoids plugin host/registry initialization and keeps output minimal.
let has_json = std::env::var("NYASH_VERIFY_JSON").is_ok(); let has_json = std::env::var("NYASH_VERIFY_JSON").is_ok();
let route = nyash_rust::config::env::env_bool("HAKO_ROUTE_HAKOVM") let route = nyash_rust::config::env::verify_primary_is_hakovm();
|| std::env::var("HAKO_VERIFY_PRIMARY").ok().as_deref() == Some("hakovm");
// Force flag may allow hv1-inline without route // Force flag may allow hv1-inline without route
let force_hv1_flag = nyash_rust::config::env::env_bool("HAKO_VERIFY_V1_FORCE_HAKOVM"); let force_hv1_flag = nyash_rust::config::env::env_bool("HAKO_VERIFY_V1_FORCE_HAKOVM");
if has_json && (route || force_hv1_flag) { 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). // 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. // This function is only called after plugins and runner initialization have already occurred.
// Selfhost pipeline (Ny -> JSON v0) // Selfhost pipeline (Ny -> JSON v0) — consolidated env toggle
// Default: ON. Backwardcompat envs: // Primary: NYASH_USE_NY_COMPILER=0|1; legacy disables accepted with deprecation warning
// - NYASH_USE_NY_COMPILER={1|true|on} to force ON if crate::config::env::use_ny_compiler() {
// - 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 {
if runner.try_run_selfhost_pipeline(filename) { if runner.try_run_selfhost_pipeline(filename) {
return; return;
} else { } 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="" NYRT_DIR=""
VERIFY=0 VERIFY=0
QUIET=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 while [[ $# -gt 0 ]]; do
case "$1" in case "$1" in
@ -51,10 +61,13 @@ if [[ -z "$OUT" ]]; then
esac esac
fi 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 if ! command -v llvm-config-18 >/dev/null 2>&1; then
echo "error: llvm-config-18 not found (install LLVM 18 dev)" >&2 echo "error: llvm-config-18 not found (install LLVM 18 dev)" >&2
exit 3 exit 3
fi fi
fi
# Build nyash + NyRT as neededskip allowed # Build nyash + NyRT as neededskip allowed
LLVM_FEATURE=${NYASH_LLVM_FEATURE:-llvm} LLVM_FEATURE=${NYASH_LLVM_FEATURE:-llvm}
@ -126,6 +139,15 @@ case "$EMIT" in
rm -f "$OUT" rm -f "$OUT"
"$BIN_NYLLVMC" --in "$IN_FILE" --emit obj --out "$OUT" >/dev/null 2>&1 || { echo "error: ny-llvmc failed" >&2; exit 4; } "$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|*) llvmlite|*)
# Directly use llvmlite harness with MIR v1 JSON input # Directly use llvmlite harness with MIR v1 JSON input
rm -f "$OUT" rm -f "$OUT"
@ -153,6 +175,22 @@ case "$EMIT" in
echo "error: ny-llvmc failed to link exe" >&2; exit 4 echo "error: ny-llvmc failed to link exe" >&2; exit 4
fi 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|*) llvmlite|*)
if ! python3 "$PWD/tools/llvmlite_harness.py" --in "$IN_FILE" --out "$OBJ" >/dev/null 2>&1; then 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 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
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." 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" TMP_JSON="/tmp/ny_crate_backend_exe_print_$$.json"
echo "$JSON" > "$TMP_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" 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 if [[ -x "$APP" ]]; then
set +e set +e
out="$($APP 2>/dev/null)"; rc=$? 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