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:
@ -3,6 +3,14 @@
|
||||
This changelog tracks high‑level milestones while Core MIR and Phase 12 evolve. For detailed per‑file history, see git log and docs under `docs/development/roadmap/`.
|
||||
|
||||
## 2025‑09‑06
|
||||
|
||||
### Phase 22.3 (Kernel Minimal C Runtime — design wrap)
|
||||
- Added minimal C runtime crate (design-stage): `crates/nyash_kernel_min_c` (staticlib).
|
||||
- LLVM extern lowering: normalized `nyash.console.*` → `nyash_console_*` for C linkage.
|
||||
- Hako-first MIR emit stabilized via wrapper (`tools/hakorune_emit_mir.sh`): Stage‑B JSON is emitted with `NYASH_JSON_ONLY=1` and sanitized; builder falls back to Rust CLI on failure (defaults keep quick green).
|
||||
|
||||
### Prep for Phase 21.10 (LLVM line — crate backend)
|
||||
- Backend selector and S3 canaries exist; print EXE canary currently SKIP pending small normalization. Next: enable print EXE PASS with env‑guarded normalization in ny‑llvmc (no default behavior changes).
|
||||
- Core‑13 flip complete: code/tests enforce Core‑13 minimal kernel. Normalizations (Array/Ref→BoxCall, TypeCheck/Cast/Barrier/WeakRef unification) are ON by default via env (NYASH_MIR_CORE13=1). New tests validate normalization.
|
||||
- Docs synced: step‑50 marked done; DEV quickstart points to Core‑13 reference.
|
||||
|
||||
|
||||
@ -1,4 +1,26 @@
|
||||
# Current Task — Phase 21.4(Hako Parser → Analyzer / Self‑Host)
|
||||
# Current Task — Phase 21.10(LLVM line – crate backend print EXE)
|
||||
|
||||
Status (22.3 wrap)
|
||||
- 22.3 締め: 最小Cランタイム(設計)/Cシンボル整合(nyash.console.*→nyash_console_*)を反映。
|
||||
- Hako-first MIR emit は wrapper 経由で安定(Stage‑B 出力の RC 混入を抑止、Hako→失敗時は Rust CLI にフォールバック)。
|
||||
- 緑条件は quick 代表セット + phase2231 canary(rc=42)で確認済み。
|
||||
|
||||
Next (this phase) — 22.x continuation
|
||||
1) TLV配線(既定OFF)+ parityカナリア
|
||||
- 既存の `nyash-tlv`(optional / feature `tlv-shim`)を `src/runtime/plugin_ffi_common.rs` に薄く配線。
|
||||
- 制御: feature + `HAKO_TLV_SHIM=1`(トレース `HAKO_TLV_SHIM_TRACE{,_DETAIL}`)。
|
||||
- 受け入れ: ON/OFF で実行/rc 同一(parity)+ トレース観測が可能。
|
||||
|
||||
2) SSOTメッセージ・相対推定の整形 + 代表カナリアの常時化
|
||||
- 曖昧時のメッセージ統一(件数+先頭N、legacy委譲の明記)。
|
||||
- cwd vs using_paths 優先の明文化・軽量canaryを quick 常時化。
|
||||
|
||||
3) ビルダーの JsonFragBox / PatternUtilBox 採用(差分小さい箇所から)
|
||||
- 手書きスキャンの置換を段階導入。If/Compare VarInt / Return BinOp VarVar 周辺を優先。
|
||||
|
||||
4) C‑core 一点通し(Map.set)+ parity維持(既定OFF)
|
||||
- feature+ENV で no‑op 経路を通し、ON/OFF parity をカナリアで検証。
|
||||
|
||||
|
||||
目的(このフェーズで到達するゴール)
|
||||
- Hako Parser(MVP)で AST JSON v0 を出力し、Analyzer の一次入力に採用(text は fallback 維持)。
|
||||
@ -41,6 +63,10 @@ Toggles quicklist
|
||||
- EXE‑first: `SMOKES_ENABLE_SELFHOST=1`(既定OFF)
|
||||
- TLV: `--features tlv-shim` + `HAKO_TLV_SHIM=1`(既定OFF/配線は無害な identity)
|
||||
- Using SSOT: `HAKO_USING_SSOT=1`(MVP は現行解決ロジックを経由しつつタグ出力)
|
||||
- ENV consolidation(既定不変)
|
||||
- NY compiler: 主 `NYASH_USE_NY_COMPILER`、alias `NYASH_DISABLE_NY_COMPILER`/`HAKO_DISABLE_NY_COMPILER`(受理+警告、一度だけ)
|
||||
- LLVM opt: 主 `NYASH_LLVM_OPT_LEVEL`、alias `HAKO_LLVM_OPT_LEVEL`(受理+警告、一度だけ)
|
||||
- Gate‑C: 主 `NYASH_GATE_C_CORE`、alias `HAKO_GATE_C_CORE`(受理+警告、一度だけ)
|
||||
|
||||
22.1 progress (today)
|
||||
- TLV配線(最小導線・既定OFF)
|
||||
|
||||
12
README.md
12
README.md
@ -4,6 +4,18 @@
|
||||
**A Seriously-Crafted Hobby Language**
|
||||
**From Zero to Native Binary in 20 Days - The AI-Powered Language Revolution**
|
||||
|
||||
Quick — Emit MIR (Hako‑first helper)
|
||||
- Generate MIR(JSON) from a Hako file using the Stage‑B parser + MirBuilder (wrapper falls back to the Rust CLI builder on failure to keep runs green):
|
||||
|
||||
```
|
||||
tools/hakorune_emit_mir.sh path/to/program.hako /tmp/program.mir.json
|
||||
target/release/hakorune --mir-json-file /tmp/program.mir.json
|
||||
```
|
||||
|
||||
Notes
|
||||
- The wrapper runs Stage‑B with `NYASH_JSON_ONLY=1` to keep the output clean (no `RC:` lines).
|
||||
- When the Hako MirBuilder fails (e.g., under development), it automatically falls back to `--program-json-to-mir` (no behavior change by default).
|
||||
|
||||
*[🇯🇵 日本語版はこちら / Japanese Version](README.ja.md)*
|
||||
|
||||
[](https://github.com/moe-charm/nyash/actions/workflows/selfhost-minimal.yml)
|
||||
|
||||
@ -6,6 +6,7 @@ use std::process::Command;
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
use clap::{ArgAction, Parser};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(
|
||||
@ -86,29 +87,59 @@ fn main() -> Result<()> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Prepare input JSON path: either from file or stdin -> temp file
|
||||
// Prepare input JSON path: either from file or stdin -> temp file.
|
||||
// Optionally normalize canary JSON into the shape expected by the Python builder
|
||||
// when HAKO_LLVM_CANARY_NORMALIZE=1 (no default behavior change).
|
||||
let mut temp_path: Option<PathBuf> = None;
|
||||
let canary_norm = env::var("HAKO_LLVM_CANARY_NORMALIZE").ok().as_deref() == Some("1");
|
||||
let input_path = if args.infile == "-" {
|
||||
let mut buf = String::new();
|
||||
std::io::stdin()
|
||||
.read_to_string(&mut buf)
|
||||
.context("reading MIR JSON from stdin")?;
|
||||
// Basic sanity check that it's JSON
|
||||
let _: serde_json::Value =
|
||||
let mut val: serde_json::Value =
|
||||
serde_json::from_str(&buf).context("stdin does not contain valid JSON")?;
|
||||
if canary_norm {
|
||||
val = normalize_canary_json(val);
|
||||
}
|
||||
let tmp = std::env::temp_dir().join("ny_llvmc_stdin.json");
|
||||
let mut f = File::create(&tmp).context("create temp json file")?;
|
||||
f.write_all(buf.as_bytes()).context("write temp json")?;
|
||||
let out = serde_json::to_vec(&val).context("serialize normalized json")?;
|
||||
f.write_all(&out).context("write temp json")?;
|
||||
temp_path = Some(tmp.clone());
|
||||
tmp
|
||||
} else {
|
||||
PathBuf::from(&args.infile)
|
||||
let p = PathBuf::from(&args.infile);
|
||||
if canary_norm {
|
||||
// Read file, normalize, and write to a temp path
|
||||
let mut buf = String::new();
|
||||
File::open(&p).and_then(|mut f| f.read_to_string(&mut buf)).context("read input json")?;
|
||||
let mut val: serde_json::Value = serde_json::from_str(&buf).context("input is not valid JSON")?;
|
||||
val = normalize_canary_json(val);
|
||||
let tmp = std::env::temp_dir().join("ny_llvmc_in.json");
|
||||
let mut f = File::create(&tmp).context("create temp json file")?;
|
||||
let out = serde_json::to_vec(&val).context("serialize normalized json")?;
|
||||
f.write_all(&out).context("write temp json")?;
|
||||
temp_path = Some(tmp.clone());
|
||||
tmp
|
||||
} else {
|
||||
p
|
||||
}
|
||||
};
|
||||
|
||||
if !input_path.exists() {
|
||||
bail!("input JSON not found: {}", input_path.display());
|
||||
}
|
||||
|
||||
// Optional: preflight shape/hints (best-effort; no behavior change)
|
||||
if let Ok(s) = std::fs::read_to_string(&input_path) {
|
||||
if let Ok(val) = serde_json::from_str::<JsonValue>(&s) {
|
||||
if let Some(hint) = shape_hint(&val) {
|
||||
eprintln!("[ny-llvmc/hint] {}", hint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Produce object first
|
||||
let obj_path = if emit_exe {
|
||||
let mut p = args.out.clone();
|
||||
@ -118,6 +149,20 @@ fn main() -> Result<()> {
|
||||
args.out.clone()
|
||||
};
|
||||
|
||||
// Optional: print concise shape hint in verbose mode when not normalizing
|
||||
if env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") && env::var("HAKO_LLVM_CANARY_NORMALIZE").ok().as_deref() != Some("1") {
|
||||
if let Ok(mut f) = File::open(&input_path) {
|
||||
let mut buf = String::new();
|
||||
if f.read_to_string(&mut buf).is_ok() {
|
||||
if let Ok(val) = serde_json::from_str::<serde_json::Value>(&buf) {
|
||||
if let Some(h) = shape_hint(&val) {
|
||||
eprintln!("[ny-llvmc/hint] {}", h);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
run_harness_in(&harness_path, &input_path, &obj_path).with_context(|| {
|
||||
format!(
|
||||
"failed to compile MIR JSON via harness: {}",
|
||||
@ -144,6 +189,93 @@ fn main() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Return a concise hint if the MIR JSON likely has a schema/shape mismatch for the Python harness.
|
||||
fn shape_hint(v: &JsonValue) -> Option<String> {
|
||||
// Accept both v0/v1 tolerant; only emit hint on common canary shapes
|
||||
// 1) schema_version numeric 1 rather than string "1.0"
|
||||
if let Some(sv) = v.get("schema_version") {
|
||||
if sv.is_number() {
|
||||
if sv.as_i64() == Some(1) {
|
||||
return Some("schema_version=1 detected; set to \"1.0\" or enable HAKO_LLVM_CANARY_NORMALIZE=1".into());
|
||||
}
|
||||
} else if sv.as_str() == Some("1") {
|
||||
return Some("schema_version=\"1\" detected; prefer \"1.0\" or enable HAKO_LLVM_CANARY_NORMALIZE=1".into());
|
||||
}
|
||||
}
|
||||
// 2) blocks use 'inst' instead of 'instructions'
|
||||
if let Some(funcs) = v.get("functions") {
|
||||
if let Some(arr) = funcs.as_array() {
|
||||
for f in arr {
|
||||
if let Some(blocks) = f.get("blocks").and_then(|b| b.as_array()) {
|
||||
for b in blocks {
|
||||
if b.get("inst").is_some() && b.get("instructions").is_none() {
|
||||
return Some("block key 'inst' found; rename to 'instructions' or enable HAKO_LLVM_CANARY_NORMALIZE=1".into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Normalize a very small canary JSON into the shape expected by the Python harness.
|
||||
/// - Accepts schema_version as number or string; coerces to "1.0" when 1.
|
||||
/// - Renames block key 'inst' -> 'instructions'.
|
||||
/// - Converts const {"ty":"i64","value":N} into {"value":{"type":"i64","value":N}}
|
||||
fn normalize_canary_json(mut v: serde_json::Value) -> serde_json::Value {
|
||||
use serde_json::{Map, Value};
|
||||
// schema_version: number 1 -> string "1.0"
|
||||
match v.get_mut("schema_version") {
|
||||
Some(Value::Number(n)) if n.as_i64() == Some(1) => {
|
||||
*v.get_mut("schema_version").unwrap() = Value::String("1.0".to_string());
|
||||
}
|
||||
Some(Value::String(s)) if s == "1" => {
|
||||
*v.get_mut("schema_version").unwrap() = Value::String("1.0".to_string());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// functions as array
|
||||
if let Some(funcs) = v.get_mut("functions") {
|
||||
if let Value::Array(ref mut arr) = funcs {
|
||||
for func in arr.iter_mut() {
|
||||
if let Value::Object(ref mut fm) = func {
|
||||
if let Some(blocks_v) = fm.get_mut("blocks") {
|
||||
if let Value::Array(ref mut blks) = blocks_v {
|
||||
for blk in blks.iter_mut() {
|
||||
if let Value::Object(ref mut bm) = blk {
|
||||
// Rename 'inst' -> 'instructions'
|
||||
if let Some(insts) = bm.remove("inst") {
|
||||
bm.insert("instructions".to_string(), insts);
|
||||
}
|
||||
// Normalize instructions
|
||||
if let Some(Value::Array(ref mut ins_arr)) = bm.get_mut("instructions") {
|
||||
for ins in ins_arr.iter_mut() {
|
||||
if let Value::Object(ref mut im) = ins {
|
||||
if im.get("op").and_then(|x| x.as_str()) == Some("const") {
|
||||
// if 'ty' and flat 'value' exist, wrap into typed value
|
||||
if let (Some(ty), Some(val)) = (im.remove("ty"), im.remove("value")) {
|
||||
let mut val_obj = Map::new();
|
||||
if let Value::String(ts) = ty { val_obj.insert("type".to_string(), Value::String(ts)); }
|
||||
else { val_obj.insert("type".to_string(), ty); }
|
||||
val_obj.insert("value".to_string(), val);
|
||||
im.insert("value".to_string(), Value::Object(val_obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
fn run_harness_dummy(harness: &Path, out: &Path) -> Result<()> {
|
||||
ensure_python()?;
|
||||
let mut cmd = Command::new("python3");
|
||||
@ -182,10 +314,13 @@ fn ensure_python() -> Result<()> {
|
||||
}
|
||||
|
||||
fn propagate_opt_level(cmd: &mut Command) {
|
||||
let level = env::var("HAKO_LLVM_OPT_LEVEL")
|
||||
.ok()
|
||||
.or_else(|| env::var("NYASH_LLVM_OPT_LEVEL").ok());
|
||||
let hako = env::var("HAKO_LLVM_OPT_LEVEL").ok();
|
||||
let nyash = env::var("NYASH_LLVM_OPT_LEVEL").ok();
|
||||
let level = nyash.clone().or(hako.clone());
|
||||
if let Some(level) = level {
|
||||
if hako.is_some() && nyash.is_none() {
|
||||
eprintln!("[deprecate/env] 'HAKO_LLVM_OPT_LEVEL' is deprecated; use 'NYASH_LLVM_OPT_LEVEL'");
|
||||
}
|
||||
cmd.env("HAKO_LLVM_OPT_LEVEL", &level);
|
||||
cmd.env("NYASH_LLVM_OPT_LEVEL", &level);
|
||||
}
|
||||
|
||||
@ -17,8 +17,6 @@ long nyash_box_from_i8_string(char* p) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Optional minimal stubs (not used by default; reserved for future reps)
|
||||
long nyash_array_birth_h(void) { return 1; }
|
||||
long nyash_array_length_h(long handle) { (void)handle; return 0; }
|
||||
long nyash_map_birth_h(void) { return 1; }
|
||||
long nyash_map_size_h(long handle) { (void)handle; return 0; }
|
||||
// Note: Additional array/map stubs intentionally omitted to avoid symbol
|
||||
// clashes with the full NyKernel when linked together. Keep this file minimal
|
||||
// (console only) for print canaries.
|
||||
|
||||
@ -2,6 +2,10 @@
|
||||
|
||||
This document lists the environment flags introduced or used by the Phase 22.1 work. Defaults are OFF and behavior remains unchanged unless noted.
|
||||
|
||||
- NYASH_JSON_ONLY=0|1
|
||||
- Quiet JSON pipelines: suppresses `RC:` and routine logs on stdout (diagnostics still go to stderr).
|
||||
- Used by Stage‑B → Program(JSON) emit to keep the output clean for downstream processing.
|
||||
|
||||
- HAKO_USING_SSOT=0|1
|
||||
- Enables the SSOT resolver gate in the runner pipeline.
|
||||
- When ON, resolution first consults the SSOT bridge (modules-only MVP). If not resolved, it falls back to the existing resolver.
|
||||
@ -91,6 +95,11 @@ LLVM backend selector (builder wrapper)
|
||||
- `crate`: uses `./target/release/ny-llvmc` (build with `cargo build -p nyash-llvm-compiler --release`).
|
||||
- `native`: reserved for future Hako-native builder.
|
||||
- Linking extras for `--emit exe`: pass via `HAKO_AOT_LDFLAGS` (e.g., `-static`), `ny-llvmc` consumes `--libs`.
|
||||
- Note: crate 経路では ny_main の戻り値(i64)がプロセスの終了コードに反映されます(rc mapping)。
|
||||
|
||||
- HAKO_LLVM_CANARY_NORMALIZE=0|1
|
||||
- 開発/カナリア専用の正規化スイッチ。`1` のとき、最小の JSON 形状差(`schema_version=1` → `"1.0"`、`blocks.inst` → `instructions`、`const` の `ty/value` 包装)を自動補正してからビルドします。
|
||||
- 既定は `0`(無効)。既存ツールの挙動は変わりません。`NYASH_CLI_VERBOSE=1` のとき形状ヒントを `[ny-llvmc/hint]` で出力します。
|
||||
|
||||
Name mapping note (EXE link convenience)
|
||||
- nyash.console.* は C リンク時にシンボル名 `nyash_console_*` に正規化される(ドット→アンダースコア)。
|
||||
@ -101,3 +110,19 @@ Kernel Minimal C Runtime (Phase 22.3 — design)
|
||||
- NYASH_KERNEL_C_MIN=0|1
|
||||
- Reserved toggle for enabling the minimal C runtime shims(design‑stage; defaults OFF)
|
||||
- Build: `cargo build --release -p nyash-kernel-min-c`(not linked by default)
|
||||
|
||||
ENV consolidation (aliases)
|
||||
- NY compiler path
|
||||
- Primary: `NYASH_USE_NY_COMPILER=0|1`
|
||||
- Accepted aliases (deprecated; prints a one‑time warning):
|
||||
- `NYASH_DISABLE_NY_COMPILER=1` → equivalent to `NYASH_USE_NY_COMPILER=0`
|
||||
- `HAKO_DISABLE_NY_COMPILER=1` → equivalent to `NYASH_USE_NY_COMPILER=0`
|
||||
- LLVM opt level
|
||||
- Primary: `NYASH_LLVM_OPT_LEVEL`
|
||||
- Accepted alias (deprecated; one‑time warning): `HAKO_LLVM_OPT_LEVEL`
|
||||
- Gate‑C (Core direct route)
|
||||
- Primary: `NYASH_GATE_C_CORE`
|
||||
- Accepted alias (deprecated; one‑time warning): `HAKO_GATE_C_CORE`
|
||||
|
||||
Notes
|
||||
- Primary keys are preferred and will be kept. Aliases remain accepted for a grace period and emit a concise deprecation line once per process.
|
||||
|
||||
@ -5,51 +5,51 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
static box LowerIfCompareBox {
|
||||
try_lower(program_json) {
|
||||
local s = "" + program_json
|
||||
local k_if = s.indexOf("\"type\":\"If\"")
|
||||
local k_if = JsonFragBox.index_of_from(s, "\"type\":\"If\"", 0)
|
||||
if k_if < 0 { return null }
|
||||
// cond Compare
|
||||
local k_cmp = s.indexOf("\"type\":\"Compare\"", k_if)
|
||||
local k_cmp = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", k_if)
|
||||
if k_cmp < 0 { return null }
|
||||
local k_op = s.indexOf("\"op\":", k_cmp)
|
||||
local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_cmp)
|
||||
if k_op < 0 { return null }
|
||||
local op = JsonFragBox.read_string_after(s, k_op + 5)
|
||||
if op == null { return null }
|
||||
if !(op == "<" || op == ">" || op == "<=" || op == ">=" || op == "==" || op == "!=") { return null }
|
||||
// lhs/rhs ints
|
||||
local klhs = s.indexOf("\"lhs\":{", k_cmp)
|
||||
local klhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp)
|
||||
if klhs < 0 { return null }
|
||||
local ti = s.indexOf("\"type\":\"Int\"", klhs)
|
||||
local ti = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", klhs)
|
||||
if ti < 0 { return null }
|
||||
local kv_lhs = s.indexOf("\"value\":", ti)
|
||||
local kv_lhs = JsonFragBox.index_of_from(s, "\"value\":", ti)
|
||||
if kv_lhs < 0 { return null }
|
||||
local lhs_val = JsonFragBox.read_int_after(s, kv_lhs + 8)
|
||||
if lhs_val == null { return null }
|
||||
local krhs = s.indexOf("\"rhs\":{", k_cmp)
|
||||
local krhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp)
|
||||
if krhs < 0 { return null }
|
||||
local ti2 = s.indexOf("\"type\":\"Int\"", krhs)
|
||||
local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", krhs)
|
||||
if ti2 < 0 { return null }
|
||||
local kv_rhs = s.indexOf("\"value\":", ti2)
|
||||
local kv_rhs = JsonFragBox.index_of_from(s, "\"value\":", ti2)
|
||||
if kv_rhs < 0 { return null }
|
||||
local rhs_val = JsonFragBox.read_int_after(s, kv_rhs + 8)
|
||||
if rhs_val == null { return null }
|
||||
// then/else return ints
|
||||
local kth = s.indexOf("\"then\":", k_if)
|
||||
local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if)
|
||||
if kth < 0 { return null }
|
||||
local rt = s.indexOf("\"type\":\"Return\"", kth)
|
||||
local rt = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth)
|
||||
if rt < 0 { return null }
|
||||
local ti3 = s.indexOf("\"type\":\"Int\"", rt)
|
||||
local ti3 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt)
|
||||
if ti3 < 0 { return null }
|
||||
local kv_then = s.indexOf("\"value\":", ti3)
|
||||
local kv_then = JsonFragBox.index_of_from(s, "\"value\":", ti3)
|
||||
if kv_then < 0 { return null }
|
||||
local then_val = JsonFragBox.read_int_after(s, kv_then + 8)
|
||||
if then_val == null { return null }
|
||||
local kel = s.indexOf("\"else\":", k_if)
|
||||
local kel = JsonFragBox.index_of_from(s, "\"else\":", k_if)
|
||||
if kel < 0 { return null }
|
||||
local rt2 = s.indexOf("\"type\":\"Return\"", kel)
|
||||
local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kel)
|
||||
if rt2 < 0 { return null }
|
||||
local ti4 = s.indexOf("\"type\":\"Int\"", rt2)
|
||||
local ti4 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2)
|
||||
if ti4 < 0 { return null }
|
||||
local kv_else = s.indexOf("\"value\":", ti4)
|
||||
local kv_else = JsonFragBox.index_of_from(s, "\"value\":", ti4)
|
||||
if kv_else < 0 { return null }
|
||||
local else_val = JsonFragBox.read_int_after(s, kv_else + 8)
|
||||
if else_val == null { return null }
|
||||
|
||||
@ -7,15 +7,15 @@ using selfhost.shared.mir.schema as MirSchemaBox
|
||||
static box LowerIfCompareFoldBinIntsBox {
|
||||
_fold_bin_ints(s, k_bin_start) {
|
||||
// expects: {"type":"Binary","op":"+|-|*|/","lhs":{"type":"Int","value":L},"rhs":{"type":"Int","value":R}}
|
||||
local kop = s.indexOf("\"op\":\"", k_bin_start); if kop < 0 { return null }
|
||||
local kop = JsonFragBox.index_of_from(s, "\"op\":\"", k_bin_start); if kop < 0 { return null }
|
||||
local iop = kop + 6; local op = s.substring(iop, iop+1)
|
||||
if !(op == "+" || op == "-" || op == "*" || op == "/") { return null }
|
||||
local kli = s.indexOf("\"type\":\"Int\"", k_bin_start); if kli < 0 { return null }
|
||||
local kvl = s.indexOf("\"value\":", kli); if kvl < 0 { return null }
|
||||
local kli = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_bin_start); if kli < 0 { return null }
|
||||
local kvl = JsonFragBox.index_of_from(s, "\"value\":", kli); if kvl < 0 { return null }
|
||||
local l = JsonFragBox.read_int_after(s, kvl + 8); if l == null { return null }
|
||||
// rhs int
|
||||
local kri = s.indexOf("\"type\":\"Int\"", kli + 1); if kri < 0 { return null }
|
||||
local kv2 = s.indexOf("\"value\":", kri); if kv2 < 0 { return null }
|
||||
local kri = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", kli + 1); if kri < 0 { return null }
|
||||
local kv2 = JsonFragBox.index_of_from(s, "\"value\":", kri); if kv2 < 0 { return null }
|
||||
local r = JsonFragBox.read_int_after(s, kv2 + 8); if r == null { return null }
|
||||
// compute
|
||||
local li = 0; local ri = 0; // string to int by simple parse (assume i64 fits)
|
||||
@ -32,17 +32,17 @@ static box LowerIfCompareFoldBinIntsBox {
|
||||
// node may be Int, Binary(Int,Int), or Var with Local Int before if_pos
|
||||
if node_pos < 0 { return null }
|
||||
// Int
|
||||
if s.indexOf("\"type\":\"Int\"", node_pos) == node_pos { // best-effort
|
||||
local kv = s.indexOf("\"value\":", node_pos); if kv < 0 { return null }
|
||||
if JsonFragBox.index_of_from(s, "\"type\":\"Int\"", node_pos) == node_pos { // best-effort
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", node_pos); if kv < 0 { return null }
|
||||
return JsonFragBox.read_int_after(s, kv + 8)
|
||||
}
|
||||
// Binary
|
||||
if s.indexOf("\"type\":\"Binary\"", node_pos) == node_pos {
|
||||
if JsonFragBox.index_of_from(s, "\"type\":\"Binary\"", node_pos) == node_pos {
|
||||
return me._fold_bin_ints(s, node_pos)
|
||||
}
|
||||
// Var(name)
|
||||
if s.indexOf("\"type\":\"Var\"", node_pos) == node_pos {
|
||||
local kn = s.indexOf("\"name\":\"", node_pos); if kn < 0 { return null }
|
||||
if JsonFragBox.index_of_from(s, "\"type\":\"Var\"", node_pos) == node_pos {
|
||||
local kn = JsonFragBox.index_of_from(s, "\"name\":\"", node_pos); if kn < 0 { return null }
|
||||
local name = JsonFragBox.read_string_after(s, kn + 5); if name == null { return null }
|
||||
// find last matching Local Int before if_pos via util
|
||||
return PatternUtilBox.find_local_int_before(s, name, if_pos)
|
||||
@ -51,29 +51,29 @@ static box LowerIfCompareFoldBinIntsBox {
|
||||
}
|
||||
try_lower(program_json){
|
||||
local s = "" + program_json
|
||||
local k_if = s.indexOf("\"type\":\"If\""); if k_if < 0 { return null }
|
||||
local k_cmp = s.indexOf("\"type\":\"Compare\"", k_if); if k_cmp < 0 { return null }
|
||||
local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null }
|
||||
local k_if = JsonFragBox.index_of_from(s, "\"type\":\"If\"", 0); if k_if < 0 { return null }
|
||||
local k_cmp = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", k_if); if k_cmp < 0 { return null }
|
||||
local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_cmp); if k_op < 0 { return null }
|
||||
local sym = JsonFragBox.read_string_after(s, k_op + 5); if sym == null { return null }
|
||||
local op = PatternUtilBox.map_cmp(sym); if op == null { return null }
|
||||
// locate lhs/rhs node starts (Var/Int/Binary)
|
||||
local klhs = s.indexOf("\"lhs\":{", k_cmp); if klhs < 0 { return null }
|
||||
local krhs = s.indexOf("\"rhs\":{", k_cmp); if krhs < 0 { return null }
|
||||
local klhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp); if klhs < 0 { return null }
|
||||
local krhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp); if krhs < 0 { return null }
|
||||
local lhs_pos = klhs + 6
|
||||
local rhs_pos = krhs + 6
|
||||
local lhs_val = me._resolve_side_int(s, lhs_pos, k_if)
|
||||
local rhs_val = me._resolve_side_int(s, rhs_pos, k_if)
|
||||
if lhs_val == null || rhs_val == null { return null }
|
||||
// then/else Return(Int)
|
||||
local kth = s.indexOf("\"then\":", k_if); if kth < 0 { return null }
|
||||
local rt1 = s.indexOf("\"type\":\"Return\"", kth); if rt1 < 0 { return null }
|
||||
local ti1 = s.indexOf("\"type\":\"Int\"", rt1); if ti1 < 0 { return null }
|
||||
local kv1 = s.indexOf("\"value\":", ti1); if kv1 < 0 { return null }
|
||||
local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if); if kth < 0 { return null }
|
||||
local rt1 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth); if rt1 < 0 { return null }
|
||||
local ti1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt1); if ti1 < 0 { return null }
|
||||
local kv1 = JsonFragBox.index_of_from(s, "\"value\":", ti1); if kv1 < 0 { return null }
|
||||
local then_v = JsonFragBox.read_int_after(s, kv1 + 8); if then_v == null { return null }
|
||||
local kel = s.indexOf("\"else\":", k_if); if kel < 0 { return null }
|
||||
local rt2 = s.indexOf("\"type\":\"Return\"", kel); if rt2 < 0 { return null }
|
||||
local ti2 = s.indexOf("\"type\":\"Int\"", rt2); if ti2 < 0 { return null }
|
||||
local kv2b = s.indexOf("\"value\":", ti2); if kv2b < 0 { return null }
|
||||
local kel = JsonFragBox.index_of_from(s, "\"else\":", k_if); if kel < 0 { return null }
|
||||
local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kel); if rt2 < 0 { return null }
|
||||
local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2); if ti2 < 0 { return null }
|
||||
local kv2b = JsonFragBox.index_of_from(s, "\"value\":", ti2); if kv2b < 0 { return null }
|
||||
local else_v = JsonFragBox.read_int_after(s, kv2b + 8); if else_v == null { return null }
|
||||
// Build MIR
|
||||
local b0 = new ArrayBox(); b0.push(MirSchemaBox.inst_const(1, lhs_val)); b0.push(MirSchemaBox.inst_const(2, rhs_val)); b0.push(MirSchemaBox.inst_compare(op,1,2,3)); b0.push(MirSchemaBox.inst_branch(3,1,2))
|
||||
|
||||
@ -7,24 +7,24 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
static box LowerIfCompareFoldVarIntBox {
|
||||
_fold_bin_varint(s, k_bin, if_pos) {
|
||||
// Binary with one Var and one Int; resolve Var via Local and compute result
|
||||
local kop = s.indexOf("\"op\":\"", k_bin); if kop < 0 { return null }
|
||||
local kop = JsonFragBox.index_of_from(s, "\"op\":\"", k_bin); if kop < 0 { return null }
|
||||
local op = JsonFragBox.read_string_after(s, kop + 5)
|
||||
if !(op=="+"||op=="-"||op=="*"||op=="/") { return null }
|
||||
local klv = s.indexOf("\"lhs\":{\"type\":\"Var\"", k_bin)
|
||||
local kli = s.indexOf("\"lhs\":{\"type\":\"Int\"", k_bin)
|
||||
local krv = s.indexOf("\"rhs\":{\"type\":\"Var\"", k_bin)
|
||||
local kri = s.indexOf("\"rhs\":{\"type\":\"Int\"", k_bin)
|
||||
local klv = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\"", k_bin)
|
||||
local kli = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Int\"", k_bin)
|
||||
local krv = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\"", k_bin)
|
||||
local kri = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Int\"", k_bin)
|
||||
local vval = null; local ival = null
|
||||
if klv >= 0 && kri >= 0 {
|
||||
local kn = s.indexOf("\"name\":", klv); if kn < 0 { return null }
|
||||
local kn = JsonFragBox.index_of_from(s, "\"name\":", klv); if kn < 0 { return null }
|
||||
local name = JsonFragBox.read_string_after(s, kn + 7)
|
||||
vval = PatternUtilBox.find_local_int_before(s, name, if_pos)
|
||||
local kv = s.indexOf("\"value\":", kri); if kv < 0 { return null }
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", kri); if kv < 0 { return null }
|
||||
ival = JsonFragBox.read_int_after(s, kv + 8)
|
||||
} else if kli >= 0 && krv >= 0 {
|
||||
local kv2 = s.indexOf("\"value\":", kli); if kv2 < 0 { return null }
|
||||
local kv2 = JsonFragBox.index_of_from(s, "\"value\":", kli); if kv2 < 0 { return null }
|
||||
ival = JsonFragBox.read_int_after(s, kv2 + 8)
|
||||
local kn2 = s.indexOf("\"name\":", krv); if kn2 < 0 { return null }
|
||||
local kn2 = JsonFragBox.index_of_from(s, "\"name\":", krv); if kn2 < 0 { return null }
|
||||
local name2 = JsonFragBox.read_string_after(s, kn2 + 7)
|
||||
vval = PatternUtilBox.find_local_int_before(s, name2, if_pos)
|
||||
}
|
||||
@ -36,17 +36,17 @@ static box LowerIfCompareFoldVarIntBox {
|
||||
}
|
||||
_resolve_side(s, node_pos, if_pos) {
|
||||
// Try Int
|
||||
if s.indexOf("\"type\":\"Int\"", node_pos) == node_pos {
|
||||
local kv = s.indexOf("\"value\":", node_pos); if kv < 0 { return null }
|
||||
if JsonFragBox.index_of_from(s, "\"type\":\"Int\"", node_pos) == node_pos {
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", node_pos); if kv < 0 { return null }
|
||||
return JsonFragBox.read_int_after(s, kv + 8)
|
||||
}
|
||||
// Binary(Var,Int) or (Int,Var)
|
||||
if s.indexOf("\"type\":\"Binary\"", node_pos) == node_pos {
|
||||
if JsonFragBox.index_of_from(s, "\"type\":\"Binary\"", node_pos) == node_pos {
|
||||
return me._fold_bin_varint(s, node_pos, if_pos)
|
||||
}
|
||||
// Var → Local Int
|
||||
if s.indexOf("\"type\":\"Var\"", node_pos) == node_pos {
|
||||
local kn = s.indexOf("\"name\":", node_pos); if kn < 0 { return null }
|
||||
if JsonFragBox.index_of_from(s, "\"type\":\"Var\"", node_pos) == node_pos {
|
||||
local kn = JsonFragBox.index_of_from(s, "\"name\":", node_pos); if kn < 0 { return null }
|
||||
local name = JsonFragBox.read_string_after(s, kn + 7)
|
||||
return PatternUtilBox.find_local_int_before(s, name, if_pos)
|
||||
}
|
||||
@ -54,26 +54,26 @@ static box LowerIfCompareFoldVarIntBox {
|
||||
}
|
||||
try_lower(program_json){
|
||||
local s = "" + program_json
|
||||
local k_if = s.indexOf("\"type\":\"If\""); if k_if < 0 { return null }
|
||||
local k_cmp = s.indexOf("\"type\":\"Compare\"", k_if); if k_cmp < 0 { return null }
|
||||
local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null }
|
||||
local k_if = JsonFragBox.index_of_from(s, "\"type\":\"If\"", 0); if k_if < 0 { return null }
|
||||
local k_cmp = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", k_if); if k_cmp < 0 { return null }
|
||||
local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_cmp); if k_op < 0 { return null }
|
||||
local op_sym = JsonFragBox.read_string_after(s, k_op + 5)
|
||||
local op = PatternUtilBox.map_cmp(op_sym); if op == null { return null }
|
||||
local klhs = s.indexOf("\"lhs\":{", k_cmp); if klhs < 0 { return null }
|
||||
local krhs = s.indexOf("\"rhs\":{", k_cmp); if krhs < 0 { return null }
|
||||
local klhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp); if klhs < 0 { return null }
|
||||
local krhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp); if krhs < 0 { return null }
|
||||
local lhs = me._resolve_side(s, klhs+6, k_if)
|
||||
local rhs = me._resolve_side(s, krhs+6, k_if)
|
||||
if lhs == null || rhs == null { return null }
|
||||
// then/else Return(Int)
|
||||
local kth = s.indexOf("\"then\":", k_if); if kth < 0 { return null }
|
||||
local rt1 = s.indexOf("\"type\":\"Return\"", kth); if rt1 < 0 { return null }
|
||||
local ti1 = s.indexOf("\"type\":\"Int\"", rt1); if ti1 < 0 { return null }
|
||||
local kv1 = s.indexOf("\"value\":", ti1); if kv1 < 0 { return null }
|
||||
local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if); if kth < 0 { return null }
|
||||
local rt1 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth); if rt1 < 0 { return null }
|
||||
local ti1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt1); if ti1 < 0 { return null }
|
||||
local kv1 = JsonFragBox.index_of_from(s, "\"value\":", ti1); if kv1 < 0 { return null }
|
||||
local tv = JsonFragBox.read_int_after(s, kv1 + 8); if tv == null { return null }
|
||||
local kel = s.indexOf("\"else\":", k_if); if kel < 0 { return null }
|
||||
local rt2 = s.indexOf("\"type\":\"Return\"", kel); if rt2 < 0 { return null }
|
||||
local ti2 = s.indexOf("\"type\":\"Int\"", rt2); if ti2 < 0 { return null }
|
||||
local kv2b = s.indexOf("\"value\":", ti2); if kv2b < 0 { return null }
|
||||
local kel = JsonFragBox.index_of_from(s, "\"else\":", k_if); if kel < 0 { return null }
|
||||
local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kel); if rt2 < 0 { return null }
|
||||
local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2); if ti2 < 0 { return null }
|
||||
local kv2b = JsonFragBox.index_of_from(s, "\"value\":", ti2); if kv2b < 0 { return null }
|
||||
local ev = JsonFragBox.read_int_after(s, kv2b + 8); if ev == null { return null }
|
||||
// Build
|
||||
local b0=new ArrayBox(); b0.push(MirSchemaBox.inst_const(1,lhs)); b0.push(MirSchemaBox.inst_const(2,rhs)); b0.push(MirSchemaBox.inst_compare(op,1,2,3)); b0.push(MirSchemaBox.inst_branch(3,1,2))
|
||||
|
||||
@ -7,50 +7,51 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
static box LowerIfCompareVarIntBox {
|
||||
try_lower(program_json){
|
||||
local s = "" + program_json
|
||||
local k_if = s.indexOf("\"type\":\"If\""); if k_if < 0 { return null }
|
||||
local k_cmp = s.indexOf("\"type\":\"Compare\"", k_if); if k_cmp < 0 { return null }
|
||||
local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null }
|
||||
// Locate If → Compare → op using robust index_of_from helpers
|
||||
local k_if = JsonFragBox.index_of_from(s, "\"type\":\"If\"", 0); if k_if < 0 { return null }
|
||||
local k_cmp = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", k_if); if k_cmp < 0 { return null }
|
||||
local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_cmp); if k_op < 0 { return null }
|
||||
local op_sym = JsonFragBox.read_string_after(s, k_op + 5)
|
||||
local op = PatternUtilBox.map_cmp(op_sym); if op == null { return null }
|
||||
// Var vs Int
|
||||
local klhs_var = s.indexOf("\"lhs\":{\"type\":\"Var\"", k_cmp)
|
||||
local krhs_int = s.indexOf("\"rhs\":{\"type\":\"Int\"", k_cmp)
|
||||
local klhs_var = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\"", k_cmp)
|
||||
local krhs_int = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Int\"", k_cmp)
|
||||
local aval=null; local bval=null
|
||||
if klhs_var >= 0 && krhs_int >= 0 {
|
||||
local k_name = s.indexOf("\"name\":", klhs_var); if k_name < 0 { return null }
|
||||
local k_name = JsonFragBox.index_of_from(s, "\"name\":", klhs_var); if k_name < 0 { return null }
|
||||
local name = JsonFragBox.read_string_after(s, k_name + 7)
|
||||
aval = PatternUtilBox.find_local_int_before(s, name, k_if)
|
||||
local ki = s.indexOf("\"type\":\"Int\"", krhs_int)
|
||||
local ki = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", krhs_int)
|
||||
if ki >= 0 {
|
||||
local kv = s.indexOf("\"value\":", ki); if kv < 0 { return null }
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", ki); if kv < 0 { return null }
|
||||
bval = JsonFragBox.read_int_after(s, kv + 8)
|
||||
}
|
||||
} else {
|
||||
// Int vs Var
|
||||
local klhs_int = s.indexOf("\"lhs\":{\"type\":\"Int\"", k_cmp)
|
||||
local krhs_var = s.indexOf("\"rhs\":{\"type\":\"Var\"", k_cmp)
|
||||
local klhs_int = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Int\"", k_cmp)
|
||||
local krhs_var = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\"", k_cmp)
|
||||
if klhs_int >= 0 && krhs_var >= 0 {
|
||||
local ki2 = s.indexOf("\"type\":\"Int\"", klhs_int)
|
||||
local ki2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", klhs_int)
|
||||
if ki2 >= 0 {
|
||||
local kv2 = s.indexOf("\"value\":", ki2); if kv2 < 0 { return null }
|
||||
local kv2 = JsonFragBox.index_of_from(s, "\"value\":", ki2); if kv2 < 0 { return null }
|
||||
aval = JsonFragBox.read_int_after(s, kv2 + 8)
|
||||
}
|
||||
local k_name2 = s.indexOf("\"name\":", krhs_var); if k_name2 < 0 { return null }
|
||||
local k_name2 = JsonFragBox.index_of_from(s, "\"name\":", krhs_var); if k_name2 < 0 { return null }
|
||||
local name2 = JsonFragBox.read_string_after(s, k_name2 + 7)
|
||||
if name2 != null { bval = PatternUtilBox.find_local_int_before(s, name2, k_if) }
|
||||
}
|
||||
}
|
||||
if aval == null || bval == null { return null }
|
||||
// then/else Return(Int)
|
||||
local kth = s.indexOf("\"then\":", k_if); if kth < 0 { return null }
|
||||
local rt1 = s.indexOf("\"type\":\"Return\"", kth); if rt1 < 0 { return null }
|
||||
local ti1 = s.indexOf("\"type\":\"Int\"", rt1); if ti1 < 0 { return null }
|
||||
local kv_then = s.indexOf("\"value\":", ti1); if kv_then < 0 { return null }
|
||||
local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if); if kth < 0 { return null }
|
||||
local rt1 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth); if rt1 < 0 { return null }
|
||||
local ti1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt1); if ti1 < 0 { return null }
|
||||
local kv_then = JsonFragBox.index_of_from(s, "\"value\":", ti1); if kv_then < 0 { return null }
|
||||
local then_v = JsonFragBox.read_int_after(s, kv_then + 8); if then_v == null { return null }
|
||||
local kel = s.indexOf("\"else\":", k_if); if kel < 0 { return null }
|
||||
local rt2 = s.indexOf("\"type\":\"Return\"", kel); if rt2 < 0 { return null }
|
||||
local ti2 = s.indexOf("\"type\":\"Int\"", rt2); if ti2 < 0 { return null }
|
||||
local kv_else = s.indexOf("\"value\":", ti2); if kv_else < 0 { return null }
|
||||
local kel = JsonFragBox.index_of_from(s, "\"else\":", k_if); if kel < 0 { return null }
|
||||
local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kel); if rt2 < 0 { return null }
|
||||
local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2); if ti2 < 0 { return null }
|
||||
local kv_else = JsonFragBox.index_of_from(s, "\"value\":", ti2); if kv_else < 0 { return null }
|
||||
local else_v = JsonFragBox.read_int_after(s, kv_else + 8); if else_v == null { return null }
|
||||
// Build MIR
|
||||
local b0=new ArrayBox(); b0.push(MirSchemaBox.inst_const(1,aval)); b0.push(MirSchemaBox.inst_const(2,bval)); b0.push(MirSchemaBox.inst_compare(op,1,2,3)); b0.push(MirSchemaBox.inst_branch(3,1,2))
|
||||
|
||||
@ -11,21 +11,21 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
static box LowerIfCompareVarVarBox {
|
||||
try_lower(program_json) {
|
||||
local s = "" + program_json
|
||||
local k_if = s.indexOf("\"type\":\"If\"")
|
||||
local k_if = JsonFragBox.index_of_from(s, "\"type\":\"If\"", 0)
|
||||
if k_if < 0 { return null }
|
||||
local k_cmp = s.indexOf("\"type\":\"Compare\"", k_if)
|
||||
local k_cmp = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", k_if)
|
||||
if k_cmp < 0 { return null }
|
||||
// LHS/RHS Var names
|
||||
local lhs_name = null
|
||||
local klhs = s.indexOf("\"lhs\":{\"type\":\"Var\"", k_cmp)
|
||||
local klhs = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\"", k_cmp)
|
||||
if klhs >= 0 {
|
||||
local k_name_lhs = s.indexOf("\"name\":", klhs); if k_name_lhs < 0 { return null }
|
||||
local k_name_lhs = JsonFragBox.index_of_from(s, "\"name\":", klhs); if k_name_lhs < 0 { return null }
|
||||
lhs_name = JsonFragBox.read_string_after(s, k_name_lhs + 7)
|
||||
}
|
||||
local rhs_name = null
|
||||
local krhs = s.indexOf("\"rhs\":{\"type\":\"Var\"", k_cmp)
|
||||
local krhs = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\"", k_cmp)
|
||||
if krhs >= 0 {
|
||||
local k_name_rhs = s.indexOf("\"name\":", krhs); if k_name_rhs < 0 { return null }
|
||||
local k_name_rhs = JsonFragBox.index_of_from(s, "\"name\":", krhs); if k_name_rhs < 0 { return null }
|
||||
rhs_name = JsonFragBox.read_string_after(s, k_name_rhs + 7)
|
||||
}
|
||||
if lhs_name == null || rhs_name == null { return null }
|
||||
@ -34,21 +34,21 @@ static box LowerIfCompareVarVarBox {
|
||||
local bval = PatternUtilBox.find_local_int_before(s, rhs_name, k_if)
|
||||
if aval == null || bval == null { return null }
|
||||
// op map
|
||||
local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null }
|
||||
local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_cmp); if k_op < 0 { return null }
|
||||
local sym = JsonFragBox.read_string_after(s, k_op + 5)
|
||||
if sym == null { return null }
|
||||
local op = PatternUtilBox.map_cmp(sym)
|
||||
if op == null { return null }
|
||||
// then/else Return(Int)
|
||||
local kth = s.indexOf("\"then\":", k_if); if kth < 0 { return null }
|
||||
local rt1 = s.indexOf("\"type\":\"Return\"", kth); if rt1 < 0 { return null }
|
||||
local ti1 = s.indexOf("\"type\":\"Int\"", rt1); if ti1 < 0 { return null }
|
||||
local kv_then = s.indexOf("\"value\":", ti1); if kv_then < 0 { return null }
|
||||
local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if); if kth < 0 { return null }
|
||||
local rt1 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth); if rt1 < 0 { return null }
|
||||
local ti1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt1); if ti1 < 0 { return null }
|
||||
local kv_then = JsonFragBox.index_of_from(s, "\"value\":", ti1); if kv_then < 0 { return null }
|
||||
local then_val = JsonFragBox.read_int_after(s, kv_then + 8); if then_val == null { return null }
|
||||
local kel = s.indexOf("\"else\":", k_if); if kel < 0 { return null }
|
||||
local rt2 = s.indexOf("\"type\":\"Return\"", kel); if rt2 < 0 { return null }
|
||||
local ti2 = s.indexOf("\"type\":\"Int\"", rt2); if ti2 < 0 { return null }
|
||||
local kv_else = s.indexOf("\"value\":", ti2); if kv_else < 0 { return null }
|
||||
local kel = JsonFragBox.index_of_from(s, "\"else\":", k_if); if kel < 0 { return null }
|
||||
local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kel); if rt2 < 0 { return null }
|
||||
local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2); if ti2 < 0 { return null }
|
||||
local kv_else = JsonFragBox.index_of_from(s, "\"value\":", ti2); if kv_else < 0 { return null }
|
||||
local else_val = JsonFragBox.read_int_after(s, kv_else + 8); if else_val == null { return null }
|
||||
|
||||
// Build MIR
|
||||
|
||||
@ -19,53 +19,53 @@ using "hako.mir.builder.internal.pattern_util" as PatternUtilBox
|
||||
static box LowerIfNestedBox {
|
||||
try_lower(program_json) {
|
||||
local s = "" + program_json
|
||||
local k_if1 = s.indexOf("\"type\":\"If\"")
|
||||
local k_if1 = JsonFragBox.index_of_from(s, "\"type\":\"If\"", 0)
|
||||
if k_if1 < 0 { return null }
|
||||
local k_cmp1 = s.indexOf("\"type\":\"Compare\"", k_if1)
|
||||
local k_cmp1 = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", k_if1)
|
||||
if k_cmp1 < 0 { return null }
|
||||
local kop1 = s.indexOf("\"op\":", k_cmp1); if kop1 < 0 { return null }
|
||||
local kop1 = JsonFragBox.index_of_from(s, "\"op\":", k_cmp1); if kop1 < 0 { return null }
|
||||
local op1s = JsonFragBox.read_string_after(s, kop1 + 5); if op1s == null { return null }
|
||||
local op1 = PatternUtilBox.map_cmp(op1s); if op1 == null { return null }
|
||||
local klhs1 = s.indexOf("\"lhs\":{", k_cmp1); if klhs1 < 0 { return null }
|
||||
local ti11 = s.indexOf("\"type\":\"Int\"", klhs1); if ti11 < 0 { return null }
|
||||
local kv11 = s.indexOf("\"value\":", ti11); if kv11 < 0 { return null }
|
||||
local klhs1 = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp1); if klhs1 < 0 { return null }
|
||||
local ti11 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", klhs1); if ti11 < 0 { return null }
|
||||
local kv11 = JsonFragBox.index_of_from(s, "\"value\":", ti11); if kv11 < 0 { return null }
|
||||
local lhs1 = JsonFragBox.read_int_after(s, kv11 + 8); if lhs1 == null { return null }
|
||||
local krhs1 = s.indexOf("\"rhs\":{", k_cmp1); if krhs1 < 0 { return null }
|
||||
local ti12 = s.indexOf("\"type\":\"Int\"", krhs1); if ti12 < 0 { return null }
|
||||
local kv12 = s.indexOf("\"value\":", ti12); if kv12 < 0 { return null }
|
||||
local krhs1 = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp1); if krhs1 < 0 { return null }
|
||||
local ti12 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", krhs1); if ti12 < 0 { return null }
|
||||
local kv12 = JsonFragBox.index_of_from(s, "\"value\":", ti12); if kv12 < 0 { return null }
|
||||
local rhs1 = JsonFragBox.read_int_after(s, kv12 + 8); if rhs1 == null { return null }
|
||||
// then Return(Int A)
|
||||
local kth = s.indexOf("\"then\":", k_if1); if kth < 0 { return null }
|
||||
local rt1 = s.indexOf("\"type\":\"Return\"", kth); if rt1 < 0 { return null }
|
||||
local ti13 = s.indexOf("\"type\":\"Int\"", rt1); if ti13 < 0 { return null }
|
||||
local kv13 = s.indexOf("\"value\":", ti13); if kv13 < 0 { return null }
|
||||
local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if1); if kth < 0 { return null }
|
||||
local rt1 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth); if rt1 < 0 { return null }
|
||||
local ti13 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt1); if ti13 < 0 { return null }
|
||||
local kv13 = JsonFragBox.index_of_from(s, "\"value\":", ti13); if kv13 < 0 { return null }
|
||||
local aval = JsonFragBox.read_int_after(s, kv13 + 8); if aval == null { return null }
|
||||
// else contains nested If with Return(Int)/Return(Int)
|
||||
local kel = s.indexOf("\"else\":", k_if1); if kel < 0 { return null }
|
||||
local k_if2 = s.indexOf("\"type\":\"If\"", kel); if k_if2 < 0 { return null }
|
||||
local k_cmp2 = s.indexOf("\"type\":\"Compare\"", k_if2); if k_cmp2 < 0 { return null }
|
||||
local kop2 = s.indexOf("\"op\":", k_cmp2); if kop2 < 0 { return null }
|
||||
local kel = JsonFragBox.index_of_from(s, "\"else\":", k_if1); if kel < 0 { return null }
|
||||
local k_if2 = JsonFragBox.index_of_from(s, "\"type\":\"If\"", kel); if k_if2 < 0 { return null }
|
||||
local k_cmp2 = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", k_if2); if k_cmp2 < 0 { return null }
|
||||
local kop2 = JsonFragBox.index_of_from(s, "\"op\":", k_cmp2); if kop2 < 0 { return null }
|
||||
local op2s = JsonFragBox.read_string_after(s, kop2 + 5); if op2s == null { return null }
|
||||
local op2 = PatternUtilBox.map_cmp(op2s); if op2 == null { return null }
|
||||
local klhs2 = s.indexOf("\"lhs\":{", k_cmp2); if klhs2 < 0 { return null }
|
||||
local ti21 = s.indexOf("\"type\":\"Int\"", klhs2); if ti21 < 0 { return null }
|
||||
local kv21 = s.indexOf("\"value\":", ti21); if kv21 < 0 { return null }
|
||||
local klhs2 = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp2); if klhs2 < 0 { return null }
|
||||
local ti21 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", klhs2); if ti21 < 0 { return null }
|
||||
local kv21 = JsonFragBox.index_of_from(s, "\"value\":", ti21); if kv21 < 0 { return null }
|
||||
local lhs2 = JsonFragBox.read_int_after(s, kv21 + 8); if lhs2 == null { return null }
|
||||
local krhs2 = s.indexOf("\"rhs\":{", k_cmp2); if krhs2 < 0 { return null }
|
||||
local ti22 = s.indexOf("\"type\":\"Int\"", krhs2); if ti22 < 0 { return null }
|
||||
local kv22 = s.indexOf("\"value\":", ti22); if kv22 < 0 { return null }
|
||||
local krhs2 = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp2); if krhs2 < 0 { return null }
|
||||
local ti22 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", krhs2); if ti22 < 0 { return null }
|
||||
local kv22 = JsonFragBox.index_of_from(s, "\"value\":", ti22); if kv22 < 0 { return null }
|
||||
local rhs2 = JsonFragBox.read_int_after(s, kv22 + 8); if rhs2 == null { return null }
|
||||
// then Return(Int B)
|
||||
local kth2 = s.indexOf("\"then\":", k_if2); if kth2 < 0 { return null }
|
||||
local rt2 = s.indexOf("\"type\":\"Return\"", kth2); if rt2 < 0 { return null }
|
||||
local ti23 = s.indexOf("\"type\":\"Int\"", rt2); if ti23 < 0 { return null }
|
||||
local kv23 = s.indexOf("\"value\":", ti23); if kv23 < 0 { return null }
|
||||
local kth2 = JsonFragBox.index_of_from(s, "\"then\":", k_if2); if kth2 < 0 { return null }
|
||||
local rt2 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth2); if rt2 < 0 { return null }
|
||||
local ti23 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt2); if ti23 < 0 { return null }
|
||||
local kv23 = JsonFragBox.index_of_from(s, "\"value\":", ti23); if kv23 < 0 { return null }
|
||||
local bval = JsonFragBox.read_int_after(s, kv23 + 8); if bval == null { return null }
|
||||
// else Return(Int C)
|
||||
local kel2 = s.indexOf("\"else\":", k_if2); if kel2 < 0 { return null }
|
||||
local rt3 = s.indexOf("\"type\":\"Return\"", kel2); if rt3 < 0 { return null }
|
||||
local ti24 = s.indexOf("\"type\":\"Int\"", rt3); if ti24 < 0 { return null }
|
||||
local kv24 = s.indexOf("\"value\":", ti24); if kv24 < 0 { return null }
|
||||
local kel2 = JsonFragBox.index_of_from(s, "\"else\":", k_if2); if kel2 < 0 { return null }
|
||||
local rt3 = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kel2); if rt3 < 0 { return null }
|
||||
local ti24 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt3); if ti24 < 0 { return null }
|
||||
local kv24 = JsonFragBox.index_of_from(s, "\"value\":", ti24); if kv24 < 0 { return null }
|
||||
local cval = JsonFragBox.read_int_after(s, kv24 + 8); if cval == null { return null }
|
||||
|
||||
// Build MIR(JSON)
|
||||
|
||||
@ -10,29 +10,29 @@ static box LowerIfThenElseFollowingReturnBox {
|
||||
try_lower(program_json) {
|
||||
local s = "" + program_json
|
||||
// If with Compare(Int,Int)
|
||||
local k_if = s.indexOf("\"type\":\"If\"")
|
||||
local k_if = JsonFragBox.index_of_from(s, "\"type\":\"If\"", 0)
|
||||
if k_if < 0 { return null }
|
||||
local k_cmp = s.indexOf("\"type\":\"Compare\"", k_if)
|
||||
local k_cmp = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", k_if)
|
||||
if k_cmp < 0 { return null }
|
||||
local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null }
|
||||
local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_cmp); if k_op < 0 { return null }
|
||||
local sym = JsonFragBox.read_string_after(s, k_op + 5); if sym == null { return null }
|
||||
local op = PatternUtilBox.map_cmp(sym); if op == null { return null }
|
||||
// LHS/RHS ints
|
||||
local klhs = s.indexOf("\"lhs\":{", k_cmp); if klhs < 0 { return null }
|
||||
local ti1 = s.indexOf("\"type\":\"Int\"", klhs); if ti1 < 0 { return null }
|
||||
{ local kv = s.indexOf("\"value\":", ti1); if kv < 0 { return null }; var lhs_val = JsonFragBox.read_int_after(s, kv + 8); if lhs_val == null { return null } }
|
||||
local krhs = s.indexOf("\"rhs\":{", k_cmp); if krhs < 0 { return null }
|
||||
local ti2 = s.indexOf("\"type\":\"Int\"", krhs); if ti2 < 0 { return null }
|
||||
{ local kv2 = s.indexOf("\"value\":", ti2); if kv2 < 0 { return null }; var rhs_val = JsonFragBox.read_int_after(s, kv2 + 8); if rhs_val == null { return null } }
|
||||
local klhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp); if klhs < 0 { return null }
|
||||
local ti1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", klhs); if ti1 < 0 { return null }
|
||||
{ local kv = JsonFragBox.index_of_from(s, "\"value\":", ti1); if kv < 0 { return null }; var lhs_val = JsonFragBox.read_int_after(s, kv + 8); if lhs_val == null { return null } }
|
||||
local krhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp); if krhs < 0 { return null }
|
||||
local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", krhs); if ti2 < 0 { return null }
|
||||
{ local kv2 = JsonFragBox.index_of_from(s, "\"value\":", ti2); if kv2 < 0 { return null }; var rhs_val = JsonFragBox.read_int_after(s, kv2 + 8); if rhs_val == null { return null } }
|
||||
// then: Return(Int)
|
||||
local kth = s.indexOf("\"then\":", k_if); if kth < 0 { return null }
|
||||
local rt = s.indexOf("\"type\":\"Return\"", kth); if rt < 0 { return null }
|
||||
local ti3 = s.indexOf("\"type\":\"Int\"", rt); if ti3 < 0 { return null }
|
||||
{ local kv3 = s.indexOf("\"value\":", ti3); if kv3 < 0 { return null }; var then_val = JsonFragBox.read_int_after(s, kv3 + 8); if then_val == null { return null } }
|
||||
local kth = JsonFragBox.index_of_from(s, "\"then\":", k_if); if kth < 0 { return null }
|
||||
local rt = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", kth); if rt < 0 { return null }
|
||||
local ti3 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", rt); if ti3 < 0 { return null }
|
||||
{ local kv3 = JsonFragBox.index_of_from(s, "\"value\":", ti3); if kv3 < 0 { return null }; var then_val = JsonFragBox.read_int_after(s, kv3 + 8); if then_val == null { return null } }
|
||||
// else is omitted → following Return(Int) in Program body
|
||||
local k_after = s.indexOf("\"type\":\"Return\"", k_if + 1); if k_after < 0 { return null }
|
||||
local ti4 = s.indexOf("\"type\":\"Int\"", k_after); if ti4 < 0 { return null }
|
||||
{ local kv4 = s.indexOf("\"value\":", ti4); if kv4 < 0 { return null }; var else_val = JsonFragBox.read_int_after(s, kv4 + 8); if else_val == null { return null } }
|
||||
local k_after = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", k_if + 1); if k_after < 0 { return null }
|
||||
local ti4 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_after); if ti4 < 0 { return null }
|
||||
{ local kv4 = JsonFragBox.index_of_from(s, "\"value\":", ti4); if kv4 < 0 { return null }; var else_val = JsonFragBox.read_int_after(s, kv4 + 8); if else_val == null { return null } }
|
||||
|
||||
// Build MIR(JSON)
|
||||
local b0 = new ArrayBox()
|
||||
|
||||
@ -12,27 +12,27 @@ static box LowerLoopCountParamBox {
|
||||
local s = "" + program_json
|
||||
// Discover loop variable name from Compare first
|
||||
// We'll accept either lhs Var(name) or rhs Var(name)
|
||||
local k_loop = s.indexOf("\"type\":\"Loop\"", 0)
|
||||
local k_loop = JsonFragBox.index_of_from(s, "\"type\":\"Loop\"", 0)
|
||||
if k_loop < 0 { return null }
|
||||
local k_cmp = s.indexOf("\"type\":\"Compare\"", k_loop)
|
||||
local k_cmp = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", k_loop)
|
||||
if k_cmp < 0 { return null }
|
||||
local varname = LoopScanBox.find_loop_var_name(s, k_cmp)
|
||||
if varname == null { return null }
|
||||
|
||||
// Local <varname> = (Int init | Var initName)
|
||||
local k_local_i = s.indexOf("\"type\":\"Local\"")
|
||||
local k_local_i = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", 0)
|
||||
if k_local_i < 0 { return null }
|
||||
if s.indexOf("\"name\":\"" + varname + "\"", k_local_i) < 0 { return null }
|
||||
if JsonFragBox.index_of_from(s, "\"name\":\"" + varname + "\"", k_local_i) < 0 { return null }
|
||||
local init = null
|
||||
{
|
||||
local k_init_int = s.indexOf("\"type\":\"Int\"", k_local_i)
|
||||
local k_loop_next = s.indexOf("\"type\":\"Loop\"", k_local_i)
|
||||
local k_init_int = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_local_i)
|
||||
local k_loop_next = JsonFragBox.index_of_from(s, "\"type\":\"Loop\"", k_local_i)
|
||||
if k_init_int >= 0 && (k_loop_next < 0 || k_init_int < k_loop_next) {
|
||||
local kv_i = s.indexOf("\"value\":", k_init_int); if kv_i >= 0 { init = JsonFragBox.read_int_after(s, kv_i + 8) }
|
||||
local kv_i = JsonFragBox.index_of_from(s, "\"value\":", k_init_int); if kv_i >= 0 { init = JsonFragBox.read_int_after(s, kv_i + 8) }
|
||||
} else {
|
||||
local k_init_var = s.indexOf("\"type\":\"Var\"", k_local_i)
|
||||
local k_init_var = JsonFragBox.index_of_from(s, "\"type\":\"Var\"", k_local_i)
|
||||
if k_init_var >= 0 && (k_loop_next < 0 || k_init_var < k_loop_next) {
|
||||
local kn_i = s.indexOf("\"name\":\"", k_init_var); if kn_i < 0 { return null }
|
||||
local kn_i = JsonFragBox.index_of_from(s, "\"name\":\"", k_init_var); if kn_i < 0 { return null }
|
||||
local vname = JsonFragBox.read_string_after(s, kn_i)
|
||||
if vname != null { init = PatternUtilBox.find_local_int_before(s, vname, k_local_i) }
|
||||
}
|
||||
@ -41,22 +41,22 @@ static box LowerLoopCountParamBox {
|
||||
if init == null { return null }
|
||||
// Loop Compare normalize: accept < / <= / > / >= with Var(varname) on either side
|
||||
// op: accept '<'/'<=' with i on lhs; '>'/'>=' with i on lhs (descending); swapped '>'/'>=' with i on rhs (ascending)
|
||||
local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null }
|
||||
local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_cmp); if k_op < 0 { return null }
|
||||
local op = JsonFragBox.read_string_after(s, k_op + 5)
|
||||
if op == null { return null }
|
||||
local has_lhs_i = s.indexOf("\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0
|
||||
local has_rhs_i = s.indexOf("\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0
|
||||
local has_lhs_i = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0
|
||||
local has_rhs_i = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0
|
||||
if !has_lhs_i && !has_rhs_i { return null }
|
||||
local cmp = null
|
||||
local limit = null
|
||||
if has_lhs_i {
|
||||
// rhs Int/Var → resolve limit
|
||||
local k_rhs = s.indexOf("\"rhs\":{", k_cmp); if k_rhs < 0 { return null }
|
||||
local k_lim_t = s.indexOf("\"type\":\"Int\"", k_rhs)
|
||||
if k_lim_t >= 0 { local kv = s.indexOf("\"value\":", k_lim_t); if kv >= 0 { limit = JsonFragBox.read_int_after(s, kv + 8) } }
|
||||
local k_rhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp); if k_rhs < 0 { return null }
|
||||
local k_lim_t = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhs)
|
||||
if k_lim_t >= 0 { local kv = JsonFragBox.index_of_from(s, "\"value\":", k_lim_t); if kv >= 0 { limit = JsonFragBox.read_int_after(s, kv + 8) } }
|
||||
else {
|
||||
local k_rv = s.indexOf("\"type\":\"Var\"", k_rhs); if k_rv < 0 { return null }
|
||||
local kn = s.indexOf("\"name\":\"", k_rhs); if kn < 0 { return null }
|
||||
local k_rv = JsonFragBox.index_of_from(s, "\"type\":\"Var\"", k_rhs); if k_rv < 0 { return null }
|
||||
local kn = JsonFragBox.index_of_from(s, "\"name\":\"", k_rhs); if kn < 0 { return null }
|
||||
local lname = JsonFragBox.read_string_after(s, kn); if lname == null { return null }
|
||||
limit = PatternUtilBox.find_local_int_before(s, lname, k_cmp)
|
||||
}
|
||||
@ -69,12 +69,12 @@ static box LowerLoopCountParamBox {
|
||||
limit = norm.substring(cpos+1, norm.length())
|
||||
} else {
|
||||
if op != ">" && op != ">=" && op != "<" && op != "<=" && op != "!=" { return null }
|
||||
local k_lhs = s.indexOf("\"lhs\":{", k_cmp); if k_lhs < 0 { return null }
|
||||
local k_lim_t2 = s.indexOf("\"type\":\"Int\"", k_lhs)
|
||||
if k_lim_t2 >= 0 { local kv2 = s.indexOf("\"value\":", k_lim_t2); if kv2 >= 0 { limit = JsonFragBox.read_int_after(s, kv2 + 8) } }
|
||||
local k_lhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp); if k_lhs < 0 { return null }
|
||||
local k_lim_t2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhs)
|
||||
if k_lim_t2 >= 0 { local kv2 = JsonFragBox.index_of_from(s, "\"value\":", k_lim_t2); if kv2 >= 0 { limit = JsonFragBox.read_int_after(s, kv2 + 8) } }
|
||||
else {
|
||||
local k_lv = s.indexOf("\"type\":\"Var\"", k_lhs); if k_lv < 0 { return null }
|
||||
local kn3 = s.indexOf("\"name\":\"", k_lhs); if kn3 < 0 { return null }
|
||||
local k_lv = JsonFragBox.index_of_from(s, "\"type\":\"Var\"", k_lhs); if k_lv < 0 { return null }
|
||||
local kn3 = JsonFragBox.index_of_from(s, "\"name\":\"", k_lhs); if kn3 < 0 { return null }
|
||||
local lname3 = JsonFragBox.read_string_after(s, kn3); if lname3 == null { return null }
|
||||
limit = PatternUtilBox.find_local_int_before(s, lname3, k_cmp)
|
||||
}
|
||||
@ -86,27 +86,27 @@ static box LowerLoopCountParamBox {
|
||||
limit = norm2.substring(cpos2+1, norm2.length())
|
||||
}
|
||||
// Body increment: Local i = Binary('+', Var i, Int step)
|
||||
local k_body_i = s.indexOf("\"name\":\"" + varname + "\"", k_loop)
|
||||
local k_body_i = JsonFragBox.index_of_from(s, "\"name\":\"" + varname + "\"", k_loop)
|
||||
if k_body_i < 0 { return null }
|
||||
local k_bop = s.indexOf("\"type\":\"Binary\"", k_body_i)
|
||||
local k_bop = JsonFragBox.index_of_from(s, "\"type\":\"Binary\"", k_body_i)
|
||||
if k_bop < 0 { return null }
|
||||
// Body increment: Local i = Binary(op '+' or '-', Var i, (Int step | Var stepName))
|
||||
local bop_plus = (s.indexOf("\"op\":\"+\"", k_bop) >= 0)
|
||||
local bop_minus = (s.indexOf("\"op\":\"-\"", k_bop) >= 0)
|
||||
local bop_plus = (JsonFragBox.index_of_from(s, "\"op\":\"+\"", k_bop) >= 0)
|
||||
local bop_minus = (JsonFragBox.index_of_from(s, "\"op\":\"-\"", k_bop) >= 0)
|
||||
if (!bop_plus && !bop_minus) { return null }
|
||||
if s.indexOf("\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_bop) < 0 { return null }
|
||||
if JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_bop) < 0 { return null }
|
||||
|
||||
local step = null
|
||||
// Prefer rhs Int if present; otherwise try rhs Var and reverse-lookup its Local Int
|
||||
{
|
||||
local k_rhsb = s.indexOf("\"rhs\":{", k_bop); if k_rhsb < 0 { return null }
|
||||
local k_t_int = s.indexOf("\"type\":\"Int\"", k_rhsb)
|
||||
local k_rhsb = JsonFragBox.index_of_from(s, "\"rhs\":{", k_bop); if k_rhsb < 0 { return null }
|
||||
local k_t_int = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhsb)
|
||||
if k_t_int >= 0 {
|
||||
local kvs = s.indexOf("\"value\":", k_t_int); if kvs >= 0 { step = JsonFragBox.read_int_after(s, kvs + 8) }
|
||||
local kvs = JsonFragBox.index_of_from(s, "\"value\":", k_t_int); if kvs >= 0 { step = JsonFragBox.read_int_after(s, kvs + 8) }
|
||||
} else {
|
||||
local k_t_var = s.indexOf("\"type\":\"Var\"", k_rhsb)
|
||||
local k_t_var = JsonFragBox.index_of_from(s, "\"type\":\"Var\"", k_rhsb)
|
||||
if k_t_var < 0 { return null }
|
||||
local kns = s.indexOf("\"name\":\"", k_rhsb); if kns < 0 { return null }
|
||||
local kns = JsonFragBox.index_of_from(s, "\"name\":\"", k_rhsb); if kns < 0 { return null }
|
||||
local vname = JsonFragBox.read_string_after(s, kns); if vname == null { return null }
|
||||
step = PatternUtilBox.find_local_int_before(s, vname, k_bop)
|
||||
}
|
||||
|
||||
@ -12,38 +12,38 @@ static box LowerLoopSimpleBox {
|
||||
try_lower(program_json) {
|
||||
local s = "" + program_json
|
||||
// Find Loop with cond Compare and normalize to canonical (<) with dynamic var name
|
||||
local k_loop = s.indexOf("\"type\":\"Loop\"")
|
||||
local k_loop = JsonFragBox.index_of_from(s, "\"type\":\"Loop\"", 0)
|
||||
if k_loop < 0 { return null }
|
||||
local k_cmp = s.indexOf("\"type\":\"Compare\"", k_loop)
|
||||
local k_cmp = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", k_loop)
|
||||
if k_cmp < 0 { return null }
|
||||
// discover loop var name from cond (lhs or rhs Var)
|
||||
local varname = LoopScanBox.find_loop_var_name(s, k_cmp)
|
||||
if varname == null { return null }
|
||||
|
||||
// op: accept '<' / '<=' as-is, '!=' (with var on lhs) as '<', and swapped '>' / '>=' (with var on rhs)
|
||||
local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null }
|
||||
local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_cmp); if k_op < 0 { return null }
|
||||
local op = JsonFragBox.read_string_after(s, k_op + 5)
|
||||
if op == null { return null }
|
||||
// Determine where Var(varname) is and extract the Int from the opposite side
|
||||
local has_lhs_i = s.indexOf("\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0
|
||||
local has_rhs_i = s.indexOf("\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0
|
||||
local has_lhs_i = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0
|
||||
local has_rhs_i = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0
|
||||
if !has_lhs_i && !has_rhs_i { return null }
|
||||
|
||||
local swapped = 0
|
||||
local limit = null
|
||||
if has_lhs_i {
|
||||
// rhs Int value
|
||||
local k_rhs = s.indexOf("\"rhs\":{", k_cmp); if k_rhs < 0 { return null }
|
||||
local k_ti = s.indexOf("\"type\":\"Int\"", k_rhs); if k_ti < 0 { return null }
|
||||
local k_v = s.indexOf("\"value\":", k_ti); if k_v < 0 { return null }
|
||||
local k_rhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp); if k_rhs < 0 { return null }
|
||||
local k_ti = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhs); if k_ti < 0 { return null }
|
||||
local k_v = JsonFragBox.index_of_from(s, "\"value\":", k_ti); if k_v < 0 { return null }
|
||||
limit = JsonFragBox.read_int_after(s, k_v + 8)
|
||||
if limit == null { return null }
|
||||
} else {
|
||||
// Var is on rhs; lhs must be Int
|
||||
swapped = 1
|
||||
local k_lhs = s.indexOf("\"lhs\":{", k_cmp); if k_lhs < 0 { return null }
|
||||
local k_ti2 = s.indexOf("\"type\":\"Int\"", k_lhs); if k_ti2 < 0 { return null }
|
||||
local k_v2 = s.indexOf("\"value\":", k_ti2); if k_v2 < 0 { return null }
|
||||
local k_lhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp); if k_lhs < 0 { return null }
|
||||
local k_ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhs); if k_ti2 < 0 { return null }
|
||||
local k_v2 = JsonFragBox.index_of_from(s, "\"value\":", k_ti2); if k_v2 < 0 { return null }
|
||||
limit = JsonFragBox.read_int_after(s, k_v2 + 8)
|
||||
if limit == null { return null }
|
||||
}
|
||||
|
||||
@ -21,19 +21,19 @@ static box LowerLoopSumBcBox {
|
||||
print("[sum_bc] enter lower")
|
||||
}
|
||||
// Loop and Compare normalize to canonical (<) with dynamic var name
|
||||
local k_loop = s.indexOf("\"type\":\"Loop\"")
|
||||
local k_loop = JsonFragBox.index_of_from(s, "\"type\":\"Loop\"", 0)
|
||||
if k_loop < 0 { return null }
|
||||
local k_cmp = s.indexOf("\"type\":\"Compare\"", k_loop)
|
||||
local k_cmp = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", k_loop)
|
||||
if k_cmp < 0 { return null }
|
||||
// discover loop var name from cond (lhs or rhs Var)
|
||||
local varname = null
|
||||
{
|
||||
local kl = s.indexOf("\"lhs\":{", k_cmp); local kr = s.indexOf("\"rhs\":{", k_cmp)
|
||||
if kl >= 0 && s.indexOf("\"type\":\"Var\"", kl) >= 0 {
|
||||
local kn = s.indexOf("\"name\":\"", kl); if kn >= 0 { varname = JsonFragBox.read_string_after(s, kn) }
|
||||
local kl = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp); local kr = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp)
|
||||
if kl >= 0 && JsonFragBox.index_of_from(s, "\"type\":\"Var\"", kl) >= 0 {
|
||||
local kn = JsonFragBox.index_of_from(s, "\"name\":\"", kl); if kn >= 0 { varname = JsonFragBox.read_string_after(s, kn) }
|
||||
}
|
||||
if varname == null && kr >= 0 && s.indexOf("\"type\":\"Var\"", kr) >= 0 {
|
||||
local kn2 = s.indexOf("\"name\":\"", kr); if kn2 >= 0 { varname = JsonFragBox.read_string_after(s, kn2) }
|
||||
if varname == null && kr >= 0 && JsonFragBox.index_of_from(s, "\"type\":\"Var\"", kr) >= 0 {
|
||||
local kn2 = JsonFragBox.index_of_from(s, "\"name\":\"", kr); if kn2 >= 0 { varname = JsonFragBox.read_string_after(s, kn2) }
|
||||
}
|
||||
}
|
||||
if varname == null { return null }
|
||||
@ -41,27 +41,27 @@ static box LowerLoopSumBcBox {
|
||||
print("[sum_bc] var=" + varname)
|
||||
}
|
||||
// op: accept '<'/'<=' with var on lhs; also accept swapped '>'/'>=' with var on rhs
|
||||
local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null }
|
||||
local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_cmp); if k_op < 0 { return null }
|
||||
local op = JsonFragBox.read_string_after(s, k_op + 5)
|
||||
if op == null { return null }
|
||||
local has_lhs_i = s.indexOf("\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0
|
||||
local has_rhs_i = s.indexOf("\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0
|
||||
local has_lhs_i = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0
|
||||
local has_rhs_i = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0
|
||||
if !has_lhs_i && !has_rhs_i { return null }
|
||||
local limit = null
|
||||
if has_lhs_i {
|
||||
if op != "<" && op != "<=" { return null }
|
||||
// rhs Int limit
|
||||
local k_rhs = s.indexOf("\"rhs\":{", k_cmp); if k_rhs < 0 { return null }
|
||||
local k_ti = s.indexOf("\"type\":\"Int\"", k_rhs); if k_ti < 0 { return null }
|
||||
local kv = s.indexOf("\"value\":", k_ti); if kv < 0 { return null }
|
||||
local k_rhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_cmp); if k_rhs < 0 { return null }
|
||||
local k_ti = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhs); if k_ti < 0 { return null }
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", k_ti); if kv < 0 { return null }
|
||||
limit = JsonFragBox.read_int_after(s, kv + 8); if limit == null { return null }
|
||||
if op == "<=" { limit = StringHelpers.int_to_str(JsonFragBox._str_to_int(limit) + 1) }
|
||||
} else {
|
||||
// swapped: Int on lhs, Var i on rhs, op should be '>' or '>='
|
||||
if op != ">" && op != ">=" { return null }
|
||||
local k_lhs = s.indexOf("\"lhs\":{", k_cmp); if k_lhs < 0 { return null }
|
||||
local k_ti2 = s.indexOf("\"type\":\"Int\"", k_lhs); if k_ti2 < 0 { return null }
|
||||
local kv2 = s.indexOf("\"value\":", k_ti2); if kv2 < 0 { return null }
|
||||
local k_lhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_cmp); if k_lhs < 0 { return null }
|
||||
local k_ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhs); if k_ti2 < 0 { return null }
|
||||
local kv2 = JsonFragBox.index_of_from(s, "\"value\":", k_ti2); if kv2 < 0 { return null }
|
||||
limit = JsonFragBox.read_int_after(s, kv2 + 8); if limit == null { return null }
|
||||
if op == ">=" { limit = StringHelpers.int_to_str(JsonFragBox._str_to_int(limit) + 1) }
|
||||
}
|
||||
@ -69,22 +69,24 @@ static box LowerLoopSumBcBox {
|
||||
// Break sentinel: If(cond Compare var==X or X==var) then Break
|
||||
local break_value = null
|
||||
{
|
||||
local kb = s.indexOf("\"type\":\"Break\"", k_loop)
|
||||
local kb = JsonFragBox.index_of_from(s, "\"type\":\"Break\"", k_loop)
|
||||
if kb >= 0 {
|
||||
// Find nearest previous Compare and grab rhs Int
|
||||
local kbc = s.lastIndexOf("\"type\":\"Compare\"", kb)
|
||||
if kbc >= 0 {
|
||||
// Ensure op=="==" and lhs Var i
|
||||
local kop = s.indexOf("\"op\":", kbc); local bop = null; if kop >= 0 { bop = JsonFragBox.read_string_after(s, kop + 5) }
|
||||
local kop = JsonFragBox.index_of_from(s, "\"op\":", kbc); local bop = null; if kop >= 0 { bop = JsonFragBox.read_string_after(s, kop + 5) }
|
||||
if bop != null && bop == "==" {
|
||||
local lhs_i = s.indexOf("\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kbc) >= 0
|
||||
local rhs_i = s.indexOf("\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kbc) >= 0
|
||||
local lhs_i = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kbc) >= 0
|
||||
local rhs_i = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kbc) >= 0
|
||||
if lhs_i {
|
||||
local kbi = s.indexOf("\"type\":\"Int\"", s.indexOf("\"rhs\":{", kbc))
|
||||
if kbi >= 0 { local kvb = s.indexOf("\"value\":", kbi); if kvb >= 0 { break_value = JsonFragBox.read_int_after(s, kvb + 8) } }
|
||||
local k_rhsb = JsonFragBox.index_of_from(s, "\"rhs\":{", kbc)
|
||||
local kbi = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhsb)
|
||||
if kbi >= 0 { local kvb = JsonFragBox.index_of_from(s, "\"value\":", kbi); if kvb >= 0 { break_value = JsonFragBox.read_int_after(s, kvb + 8) } }
|
||||
} else if rhs_i {
|
||||
local kbi2 = s.indexOf("\"type\":\"Int\"", s.indexOf("\"lhs\":{", kbc))
|
||||
if kbi2 >= 0 { local kvb2 = s.indexOf("\"value\":", kbi2); if kvb2 >= 0 { break_value = JsonFragBox.read_int_after(s, kvb2 + 8) } }
|
||||
local k_lhsb = JsonFragBox.index_of_from(s, "\"lhs\":{", kbc)
|
||||
local kbi2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhsb)
|
||||
if kbi2 >= 0 { local kvb2 = JsonFragBox.index_of_from(s, "\"value\":", kbi2); if kvb2 >= 0 { break_value = JsonFragBox.read_int_after(s, kvb2 + 8) } }
|
||||
}
|
||||
} else if bop != null && bop == "!=" {
|
||||
// Delegate to loop-scan helper for '!=' + else [Break]
|
||||
@ -92,11 +94,11 @@ static box LowerLoopSumBcBox {
|
||||
// Fallback: try local JsonFragBox-based extraction near kbc
|
||||
if break_value == null {
|
||||
// Read Int from lhs or rhs around kbc
|
||||
local k_rhsb = s.indexOf("\"rhs\":{", kbc); local k_lhsb = s.indexOf("\"lhs\":{", kbc)
|
||||
if k_rhsb >= 0 && s.indexOf("\"type\":\"Int\"", k_rhsb) >= 0 {
|
||||
local kvi = s.indexOf("\"value\":", s.indexOf("\"type\":\"Int\"", k_rhsb)); if kvi >= 0 { break_value = JsonFragBox.read_int_after(s, kvi + 8) }
|
||||
} else if k_lhsb >= 0 && s.indexOf("\"type\":\"Int\"", k_lhsb) >= 0 {
|
||||
local kvj = s.indexOf("\"value\":", s.indexOf("\"type\":\"Int\"", k_lhsb)); if kvj >= 0 { break_value = JsonFragBox.read_int_after(s, kvj + 8) }
|
||||
local k_rhsb = JsonFragBox.index_of_from(s, "\"rhs\":{", kbc); local k_lhsb = JsonFragBox.index_of_from(s, "\"lhs\":{", kbc)
|
||||
if k_rhsb >= 0 && JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhsb) >= 0 {
|
||||
local kvi = JsonFragBox.index_of_from(s, "\"value\":", JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhsb)); if kvi >= 0 { break_value = JsonFragBox.read_int_after(s, kvi + 8) }
|
||||
} else if k_lhsb >= 0 && JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhsb) >= 0 {
|
||||
local kvj = JsonFragBox.index_of_from(s, "\"value\":", JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhsb)); if kvj >= 0 { break_value = JsonFragBox.read_int_after(s, kvj + 8) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -106,31 +108,33 @@ static box LowerLoopSumBcBox {
|
||||
// Continue sentinel: If(cond Compare var==Y or Y==var) then Continue
|
||||
local skip_value = null
|
||||
{
|
||||
local kc = s.indexOf("\"type\":\"Continue\"", k_loop)
|
||||
local kc = JsonFragBox.index_of_from(s, "\"type\":\"Continue\"", k_loop)
|
||||
if kc >= 0 {
|
||||
local kcc = s.lastIndexOf("\"type\":\"Compare\"", kc)
|
||||
if kcc >= 0 {
|
||||
local kop2 = s.indexOf("\"op\":", kcc); local cop = null; if kop2 >= 0 { cop = JsonFragBox.read_string_after(s, kop2 + 5) }
|
||||
local kop2 = JsonFragBox.index_of_from(s, "\"op\":", kcc); local cop = null; if kop2 >= 0 { cop = JsonFragBox.read_string_after(s, kop2 + 5) }
|
||||
if cop != null && cop == "==" {
|
||||
local lhs_i2 = s.indexOf("\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kcc) >= 0
|
||||
local rhs_i2 = s.indexOf("\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kcc) >= 0
|
||||
local lhs_i2 = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kcc) >= 0
|
||||
local rhs_i2 = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kcc) >= 0
|
||||
if lhs_i2 {
|
||||
local kci = s.indexOf("\"type\":\"Int\"", s.indexOf("\"rhs\":{", kcc))
|
||||
if kci >= 0 { local kvs = s.indexOf("\"value\":", kci); if kvs >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs + 8) } }
|
||||
local k_rhsb2 = JsonFragBox.index_of_from(s, "\"rhs\":{", kcc)
|
||||
local kci = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhsb2)
|
||||
if kci >= 0 { local kvs = JsonFragBox.index_of_from(s, "\"value\":", kci); if kvs >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs + 8) } }
|
||||
} else if rhs_i2 {
|
||||
local kci2 = s.indexOf("\"type\":\"Int\"", s.indexOf("\"lhs\":{", kcc))
|
||||
if kci2 >= 0 { local kvs2 = s.indexOf("\"value\":", kci2); if kvs2 >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs2 + 8) } }
|
||||
local k_lhsb2 = JsonFragBox.index_of_from(s, "\"lhs\":{", kcc)
|
||||
local kci2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhsb2)
|
||||
if kci2 >= 0 { local kvs2 = JsonFragBox.index_of_from(s, "\"value\":", kci2); if kvs2 >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs2 + 8) } }
|
||||
}
|
||||
} else if cop != null && cop == "!=" {
|
||||
// Delegate to loop-scan helper for '!=' + else [Continue]
|
||||
if skip_value == null { skip_value = LoopScanBox.extract_ne_else_sentinel_value(s, "Continue", k_loop, varname) }
|
||||
// Fallback: JsonFragBox-based local extraction near kcc
|
||||
if skip_value == null {
|
||||
local k_rhsb2 = s.indexOf("\"rhs\":{", kcc); local k_lhsb2 = s.indexOf("\"lhs\":{", kcc)
|
||||
if k_rhsb2 >= 0 && s.indexOf("\"type\":\"Int\"", k_rhsb2) >= 0 {
|
||||
local kvs = s.indexOf("\"value\":", s.indexOf("\"type\":\"Int\"", k_rhsb2)); if kvs >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs + 8) }
|
||||
} else if k_lhsb2 >= 0 && s.indexOf("\"type\":\"Int\"", k_lhsb2) >= 0 {
|
||||
local kvs2 = s.indexOf("\"value\":", s.indexOf("\"type\":\"Int\"", k_lhsb2)); if kvs2 >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs2 + 8) }
|
||||
local k_rhsb2x = JsonFragBox.index_of_from(s, "\"rhs\":{", kcc); local k_lhsb2x = JsonFragBox.index_of_from(s, "\"lhs\":{", kcc)
|
||||
if k_rhsb2x >= 0 && JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhsb2x) >= 0 {
|
||||
local kvs = JsonFragBox.index_of_from(s, "\"value\":", JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_rhsb2x)); if kvs >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs + 8) }
|
||||
} else if k_lhsb2x >= 0 && JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhsb2x) >= 0 {
|
||||
local kvs2 = JsonFragBox.index_of_from(s, "\"value\":", JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_lhsb2x)); if kvs2 >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs2 + 8) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,8 +5,8 @@ static box LowerMethodArrayGetSetBox {
|
||||
try_lower(program_json) {
|
||||
if program_json == null { return null }
|
||||
local s = "" + program_json
|
||||
if s.indexOf("\"type\":\"New\"") < 0 { return null }
|
||||
if s.indexOf("\"class\":\"ArrayBox\"") < 0 { return null }
|
||||
if JsonFragBox.index_of_from(s, "\"type\":\"New\"", 0) < 0 { return null }
|
||||
if JsonFragBox.index_of_from(s, "\"class\":\"ArrayBox\"", 0) < 0 { return null }
|
||||
// Reverse-lookup (safe subset): prefer Local(Int) for index, Local(String) for value
|
||||
local n = s.length()
|
||||
local idx = PatternUtilBox.find_any_local_int_before(s, n)
|
||||
|
||||
@ -5,8 +5,8 @@ static box LowerMethodArrayPushBox {
|
||||
try_lower(program_json) {
|
||||
if program_json == null { return null }
|
||||
local s = "" + program_json
|
||||
if s.indexOf("\"type\":\"New\"") < 0 { return null }
|
||||
if s.indexOf("\"class\":\"ArrayBox\"") < 0 { return null }
|
||||
if JsonFragBox.index_of_from(s, "\"type\":\"New\"", 0) < 0 { return null }
|
||||
if JsonFragBox.index_of_from(s, "\"class\":\"ArrayBox\"", 0) < 0 { return null }
|
||||
// Reverse-lookup (safe subset): prefer Local(Int) for push values when present
|
||||
local n = s.length()
|
||||
local p1 = PatternUtilBox.find_any_local_int_before(s, n); if p1 == null { p1 = "1" }
|
||||
|
||||
@ -5,8 +5,8 @@ static box LowerMethodArraySizeBox {
|
||||
try_lower(program_json) {
|
||||
if program_json == null { return null }
|
||||
local s = "" + program_json
|
||||
if s.indexOf("\"type\":\"New\"") < 0 { return null }
|
||||
if s.indexOf("\"class\":\"ArrayBox\"") < 0 { return null }
|
||||
if JsonFragBox.index_of_from(s, "\"type\":\"New\"", 0) < 0 { return null }
|
||||
if JsonFragBox.index_of_from(s, "\"class\":\"ArrayBox\"", 0) < 0 { return null }
|
||||
// Emit MIR v1 JSON: new ArrayBox -> r1, size(r1) -> r2, const 0 -> r3, ret r3
|
||||
local json = "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[{\"name\":\"main\",\"blocks\":[{\"id\":0,\"instructions\":[" +
|
||||
"{\"op\":\"mir_call\",\"dst\":1,\"mir_call\":{\"callee\":{\"type\":\"Constructor\",\"box_type\":\"ArrayBox\"},\"args\":[],\"effects\":[]}}," +
|
||||
@ -16,4 +16,3 @@ static box LowerMethodArraySizeBox {
|
||||
return json
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5,8 +5,8 @@ static box LowerMethodMapGetSetBox {
|
||||
try_lower(program_json) {
|
||||
if program_json == null { return null }
|
||||
local s = "" + program_json
|
||||
if s.indexOf("\"type\":\"New\"") < 0 { return null }
|
||||
if s.indexOf("\"class\":\"MapBox\"") < 0 { return null }
|
||||
if JsonFragBox.index_of_from(s, "\"type\":\"New\"", 0) < 0 { return null }
|
||||
if JsonFragBox.index_of_from(s, "\"class\":\"MapBox\"", 0) < 0 { return null }
|
||||
// Reverse-lookup (safe subset): prefer Local(String) for key, Local(Int) for value
|
||||
local n = s.length()
|
||||
local key = PatternUtilBox.find_any_local_string_before(s, n)
|
||||
|
||||
@ -4,8 +4,8 @@ static box LowerMethodMapSizeBox {
|
||||
try_lower(program_json) {
|
||||
if program_json == null { return null }
|
||||
local s = "" + program_json
|
||||
if s.indexOf("\"type\":\"New\"") < 0 { return null }
|
||||
if s.indexOf("\"class\":\"MapBox\"") < 0 { return null }
|
||||
if JsonFragBox.index_of_from(s, "\"type\":\"New\"", 0) < 0 { return null }
|
||||
if JsonFragBox.index_of_from(s, "\"class\":\"MapBox\"", 0) < 0 { return null }
|
||||
local json = "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[{\"name\":\"main\",\"blocks\":[{\"id\":0,\"instructions\":[" +
|
||||
"{\"op\":\"mir_call\",\"dst\":1,\"mir_call\":{\"callee\":{\"type\":\"Constructor\",\"box_type\":\"MapBox\"},\"args\":[],\"effects\":[]}}," +
|
||||
"{\"op\":\"mir_call\",\"dst\":2,\"mir_call\":{\"callee\":{\"type\":\"Method\",\"box_name\":\"MapBox\",\"method\":\"size\",\"receiver\":1},\"args\":[],\"effects\":[]}}," +
|
||||
@ -14,4 +14,3 @@ static box LowerMethodMapSizeBox {
|
||||
return json
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7,11 +7,11 @@ static box LowerNewboxConstructorBox {
|
||||
if program_json == null { return null }
|
||||
local s = "" + program_json
|
||||
// Quick pattern check
|
||||
if s.indexOf("\"type\":\"New\"") < 0 { return null }
|
||||
if JsonFragBox.index_of_from(s, "\"type\":\"New\"", 0) < 0 { return null }
|
||||
// Find class name (minimal scan)
|
||||
local cls = null
|
||||
if s.indexOf("\"class\":\"ArrayBox\"") >= 0 { cls = "ArrayBox" }
|
||||
else { if s.indexOf("\"class\":\"MapBox\"") >= 0 { cls = "MapBox" } }
|
||||
if JsonFragBox.index_of_from(s, "\"class\":\"ArrayBox\"", 0) >= 0 { cls = "ArrayBox" }
|
||||
else { if JsonFragBox.index_of_from(s, "\"class\":\"MapBox\"", 0) >= 0 { cls = "MapBox" } }
|
||||
if cls == null { return null }
|
||||
// Only accept known minimal boxes
|
||||
if !(cls == "ArrayBox" || cls == "MapBox") { return null }
|
||||
|
||||
@ -5,34 +5,34 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
static box LowerReturnBinOpBox {
|
||||
try_lower(program_json) {
|
||||
local s = "" + program_json
|
||||
local k_ret = s.indexOf("\"type\":\"Return\"")
|
||||
local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0)
|
||||
if k_ret < 0 { return null }
|
||||
local k_bin = s.indexOf("\"type\":\"Binary\"", k_ret)
|
||||
local k_bin = JsonFragBox.index_of_from(s, "\"type\":\"Binary\"", k_ret)
|
||||
if k_bin < 0 { return null }
|
||||
// op
|
||||
local k_op = s.indexOf("\"op\":", k_bin)
|
||||
local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_bin)
|
||||
if k_op < 0 { return null }
|
||||
local op = JsonFragBox.read_string_after(s, k_op + 5)
|
||||
if op == null { return null }
|
||||
if !(op == "+" || op == "-" || op == "*" || op == "/") { return null }
|
||||
// lhs/rhs object starts
|
||||
local klhs = s.indexOf("\"lhs\":{", k_bin)
|
||||
local krhs = s.indexOf("\"rhs\":{", k_bin)
|
||||
local klhs = JsonFragBox.index_of_from(s, "\"lhs\":{", k_bin)
|
||||
local krhs = JsonFragBox.index_of_from(s, "\"rhs\":{", k_bin)
|
||||
if klhs < 0 { return null }
|
||||
// strictly ensure lhs node is Int by bounding search before rhs start
|
||||
local ti = s.indexOf("\"type\":\"Int\"", klhs)
|
||||
local ti = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", klhs)
|
||||
if ti < 0 { return null }
|
||||
if krhs >= 0 && ti >= krhs { return null }
|
||||
local kv_lhs = s.indexOf("\"value\":", ti)
|
||||
local kv_lhs = JsonFragBox.index_of_from(s, "\"value\":", ti)
|
||||
if kv_lhs < 0 { return null }
|
||||
if krhs >= 0 && kv_lhs >= krhs { return null }
|
||||
local lhs_val = JsonFragBox.read_int_after(s, kv_lhs + 8)
|
||||
if lhs_val == null { return null }
|
||||
// rhs int
|
||||
if krhs < 0 { return null }
|
||||
local ti2 = s.indexOf("\"type\":\"Int\"", krhs)
|
||||
local ti2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", krhs)
|
||||
if ti2 < 0 { return null }
|
||||
local kv_rhs = s.indexOf("\"value\":", ti2)
|
||||
local kv_rhs = JsonFragBox.index_of_from(s, "\"value\":", ti2)
|
||||
if kv_rhs < 0 { return null }
|
||||
local rhs_val = JsonFragBox.read_int_after(s, kv_rhs + 8)
|
||||
if rhs_val == null { return null }
|
||||
|
||||
@ -10,26 +10,27 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
static box LowerReturnBinOpVarIntBox {
|
||||
try_lower(program_json) {
|
||||
local s = "" + program_json
|
||||
local k_ret = s.indexOf("\"type\":\"Return\"")
|
||||
local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0)
|
||||
if k_ret < 0 { return null }
|
||||
local k_bin = s.indexOf("\"type\":\"Binary\"", k_ret)
|
||||
local k_bin = JsonFragBox.index_of_from(s, "\"type\":\"Binary\"", k_ret)
|
||||
if k_bin < 0 { return null }
|
||||
local k_op = s.indexOf("\"op\":", k_bin)
|
||||
local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_bin)
|
||||
if k_op < 0 { return null }
|
||||
local op = JsonFragBox.read_string_after(s, k_op + 5)
|
||||
if op == null { return null }
|
||||
if !(op == "+" || op == "-" || op == "*" || op == "/") { return null }
|
||||
// Map op symbol to MIR op_kind via shared util
|
||||
local kind = PatternUtilBox.map_binop(op); if kind == null { return null }
|
||||
// Try Var + Int
|
||||
local klhs_var = s.indexOf("\"lhs\":{\"type\":\"Var\"", k_bin)
|
||||
local krhs_int = s.indexOf("\"rhs\":{\"type\":\"Int\"", k_bin)
|
||||
local klhs_var = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\"", k_bin)
|
||||
local krhs_int = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Int\"", k_bin)
|
||||
local var_name = null
|
||||
local rhs_val = null
|
||||
if klhs_var >= 0 && krhs_int >= 0 {
|
||||
local k_name = s.indexOf("\"name\":", klhs_var); if k_name < 0 { return null }
|
||||
local k_name = JsonFragBox.index_of_from(s, "\"name\":", klhs_var); if k_name < 0 { return null }
|
||||
var_name = JsonFragBox.read_string_after(s, k_name + 7)
|
||||
local kvi = s.indexOf("\"type\":\"Int\"", krhs_int)
|
||||
local kvi = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", krhs_int)
|
||||
if kvi >= 0 {
|
||||
local kv = s.indexOf("\"value\":", kvi); if kv < 0 { return null }
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", kvi); if kv < 0 { return null }
|
||||
rhs_val = JsonFragBox.read_int_after(s, kv + 8)
|
||||
}
|
||||
if var_name != null && rhs_val != null {
|
||||
@ -38,7 +39,7 @@ static box LowerReturnBinOpVarIntBox {
|
||||
local b0 = new ArrayBox()
|
||||
b0.push(MirSchemaBox.inst_const(1, var_val))
|
||||
b0.push(MirSchemaBox.inst_const(2, rhs_val))
|
||||
b0.push(MirSchemaBox.inst_binop(op == "+" ? "Add" : (op == "-" ? "Sub" : (op == "*" ? "Mul" : "Div")), 1, 2, 3))
|
||||
b0.push(MirSchemaBox.inst_binop(kind, 1, 2, 3))
|
||||
b0.push(MirSchemaBox.inst_ret(3))
|
||||
local blocks = new ArrayBox(); blocks.push(MirSchemaBox.block(0, b0))
|
||||
return MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
@ -46,17 +47,17 @@ static box LowerReturnBinOpVarIntBox {
|
||||
}
|
||||
}
|
||||
// Try Int + Var
|
||||
local klhs_int = s.indexOf("\"lhs\":{\"type\":\"Int\"", k_bin)
|
||||
local krhs_var = s.indexOf("\"rhs\":{\"type\":\"Var\"", k_bin)
|
||||
local klhs_int = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Int\"", k_bin)
|
||||
local krhs_var = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\"", k_bin)
|
||||
var_name = null
|
||||
local lhs_val = null
|
||||
if klhs_int >= 0 && krhs_var >= 0 {
|
||||
local kvi2 = s.indexOf("\"type\":\"Int\"", klhs_int)
|
||||
local kvi2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", klhs_int)
|
||||
if kvi2 >= 0 {
|
||||
local kv2 = s.indexOf("\"value\":", kvi2); if kv2 < 0 { return null }
|
||||
local kv2 = JsonFragBox.index_of_from(s, "\"value\":", kvi2); if kv2 < 0 { return null }
|
||||
lhs_val = JsonFragBox.read_int_after(s, kv2 + 8)
|
||||
}
|
||||
local k_name2 = s.indexOf("\"name\":", krhs_var); if k_name2 < 0 { return null }
|
||||
local k_name2 = JsonFragBox.index_of_from(s, "\"name\":", krhs_var); if k_name2 < 0 { return null }
|
||||
var_name = JsonFragBox.read_string_after(s, k_name2 + 7)
|
||||
if lhs_val != null && var_name != null {
|
||||
local var_val2 = PatternUtilBox.find_local_int_before(s, var_name, k_ret)
|
||||
@ -64,7 +65,7 @@ static box LowerReturnBinOpVarIntBox {
|
||||
local b1 = new ArrayBox()
|
||||
b1.push(MirSchemaBox.inst_const(1, lhs_val))
|
||||
b1.push(MirSchemaBox.inst_const(2, var_val2))
|
||||
b1.push(MirSchemaBox.inst_binop(op == "+" ? "Add" : (op == "-" ? "Sub" : (op == "*" ? "Mul" : "Div")), 1, 2, 3))
|
||||
b1.push(MirSchemaBox.inst_binop(kind, 1, 2, 3))
|
||||
b1.push(MirSchemaBox.inst_ret(3))
|
||||
local blocks = new ArrayBox(); blocks.push(MirSchemaBox.block(0, b1))
|
||||
return MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
|
||||
@ -7,20 +7,20 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
static box LowerReturnBinOpVarVarBox {
|
||||
try_lower(program_json){
|
||||
local s = "" + program_json
|
||||
local k_ret = s.indexOf("\"type\":\"Return\""); if k_ret < 0 { return null }
|
||||
local k_bin = s.indexOf("\"type\":\"Binary\"", k_ret); if k_bin < 0 { return null }
|
||||
local k_op = s.indexOf("\"op\":", k_bin); if k_op < 0 { return null }
|
||||
local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0); if k_ret < 0 { return null }
|
||||
local k_bin = JsonFragBox.index_of_from(s, "\"type\":\"Binary\"", k_ret); if k_bin < 0 { return null }
|
||||
local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_bin); if k_op < 0 { return null }
|
||||
local op = JsonFragBox.read_string_after(s, k_op + 5); if op == null { return null }
|
||||
if !(op == "+" || op == "-" || op == "*" || op == "/") { return null }
|
||||
local klhs = s.indexOf("\"lhs\":{\"type\":\"Var\"", k_bin); if klhs < 0 { return null }
|
||||
local krhs = s.indexOf("\"rhs\":{\"type\":\"Var\"", k_bin); if krhs < 0 { return null }
|
||||
local knl = s.indexOf("\"name\":", klhs); if knl < 0 { return null }
|
||||
local kind = PatternUtilBox.map_binop(op); if kind == null { return null }
|
||||
local klhs = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\"", k_bin); if klhs < 0 { return null }
|
||||
local krhs = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\"", k_bin); if krhs < 0 { return null }
|
||||
local knl = JsonFragBox.index_of_from(s, "\"name\":", klhs); if knl < 0 { return null }
|
||||
local lname = JsonFragBox.read_string_after(s, knl + 7); if lname == null { return null }
|
||||
local knr = s.indexOf("\"name\":", krhs); if knr < 0 { return null }
|
||||
local knr = JsonFragBox.index_of_from(s, "\"name\":", krhs); if knr < 0 { return null }
|
||||
local rname = JsonFragBox.read_string_after(s, knr + 7); if rname == null { return null }
|
||||
local lval = PatternUtilBox.find_local_int_before(s, lname, k_ret); if lval == null { return null }
|
||||
local rval = PatternUtilBox.find_local_int_before(s, rname, k_ret); if rval == null { return null }
|
||||
local b0=new ArrayBox(); b0.push(MirSchemaBox.inst_const(1,lval)); b0.push(MirSchemaBox.inst_const(2,rval)); b0.push(MirSchemaBox.inst_binop(op == "+" ? "Add" : (op == "-" ? "Sub" : (op == "*" ? "Mul" : "Div")),1,2,3)); b0.push(MirSchemaBox.inst_ret(3))
|
||||
local b0=new ArrayBox(); b0.push(MirSchemaBox.inst_const(1,lval)); b0.push(MirSchemaBox.inst_const(2,rval)); b0.push(MirSchemaBox.inst_binop(kind,1,2,3)); b0.push(MirSchemaBox.inst_ret(3))
|
||||
local blocks=new ArrayBox(); blocks.push(MirSchemaBox.block(0,b0));
|
||||
return MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
}
|
||||
|
||||
@ -5,16 +5,16 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
static box LowerReturnBoolBox {
|
||||
try_lower(program_json) {
|
||||
local s = "" + program_json
|
||||
local k_ret = s.indexOf("\"type\":\"Return\"")
|
||||
local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0)
|
||||
if k_ret < 0 { return null }
|
||||
// Restrict to Return(expr=Bool …): require expr 開始直後に Bool が来る
|
||||
// 例: "expr":{"type":"Bool","value":true}
|
||||
local k_expr = s.indexOf("\"expr\":", k_ret)
|
||||
local k_expr = JsonFragBox.index_of_from(s, "\"expr\":", k_ret)
|
||||
if k_expr < 0 { return null }
|
||||
local k_bool = s.indexOf("\"type\":\"Bool\"", k_expr)
|
||||
local k_bool = JsonFragBox.index_of_from(s, "\"type\":\"Bool\"", k_expr)
|
||||
if k_bool < 0 { return null }
|
||||
// Ensure this Bool belongs to the same expr (次の '}' までに value があることを確認)
|
||||
local k_val = s.indexOf("\"value\":", k_bool)
|
||||
local k_val = JsonFragBox.index_of_from(s, "\"value\":", k_bool)
|
||||
if k_val < 0 { return null }
|
||||
local is_true = JsonFragBox.read_bool_after(s, k_val+8)
|
||||
if is_true == null { return null }
|
||||
|
||||
@ -6,11 +6,11 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
static box LowerReturnFloatBox {
|
||||
try_lower(program_json) {
|
||||
local s = "" + program_json
|
||||
local k_ret = s.indexOf("\"type\":\"Return\"")
|
||||
local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0)
|
||||
if k_ret < 0 { return null }
|
||||
local k_float = s.indexOf("\"type\":\"Float\"", k_ret)
|
||||
local k_float = JsonFragBox.index_of_from(s, "\"type\":\"Float\"", k_ret)
|
||||
if k_float < 0 { return null }
|
||||
local k_val = s.indexOf("\"value\":", k_float)
|
||||
local k_val = JsonFragBox.index_of_from(s, "\"value\":", k_float)
|
||||
if k_val < 0 { return null }
|
||||
local fstr = JsonFragBox.read_float_after(s, k_val+8)
|
||||
if fstr == null { return null }
|
||||
|
||||
@ -5,14 +5,14 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
static box LowerReturnIntBox {
|
||||
try_lower(program_json) {
|
||||
local s = "" + program_json
|
||||
local k_ret = s.indexOf("\"type\":\"Return\"")
|
||||
local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0)
|
||||
if k_ret < 0 { return null }
|
||||
// Find expr object
|
||||
local k_expr = s.indexOf("\"expr\":{", k_ret)
|
||||
local k_expr = JsonFragBox.index_of_from(s, "\"expr\":{", k_ret)
|
||||
if k_expr < 0 { return null }
|
||||
// Check that expr.type is directly Int (not Binary, Logical, Var, etc)
|
||||
local k_type_start = k_expr + 8
|
||||
local k_type = s.indexOf("\"type\":", k_type_start)
|
||||
local k_type = JsonFragBox.index_of_from(s, "\"type\":", k_type_start)
|
||||
if k_type < 0 || k_type > k_type_start + 20 { return null }
|
||||
// Extract type value to verify it's "Int"
|
||||
local k_type_val = k_type + 7
|
||||
@ -28,9 +28,9 @@ static box LowerReturnIntBox {
|
||||
if k_type_val + 3 >= n { return null }
|
||||
if s.substring(k_type_val+3, k_type_val+4) != "\"" { return null }
|
||||
// Now extract the value
|
||||
local k_int = s.indexOf("\"type\":\"Int\"", k_expr)
|
||||
local k_int = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_expr)
|
||||
if k_int < 0 { return null }
|
||||
local kv = s.indexOf("\"value\":", k_int); if kv < 0 { return null }
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", k_int); if kv < 0 { return null }
|
||||
local val = JsonFragBox.read_int_after(s, kv + 8)
|
||||
if val == null { return null }
|
||||
local debug_on = 0
|
||||
|
||||
@ -11,7 +11,7 @@ static box LowerReturnLogicalBox {
|
||||
|
||||
try_lower(program_json) {
|
||||
local s = "" + program_json
|
||||
local k_ret = s.indexOf("\"type\":\"Return\"")
|
||||
local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0)
|
||||
if k_ret < 0 { return null }
|
||||
local k_log = JsonFragBox.index_of_from(s, "\"type\":\"Logical\"", k_ret)
|
||||
if k_log < 0 { return null }
|
||||
|
||||
@ -8,12 +8,12 @@ using selfhost.vm.helpers.method_alias_policy as MethodAliasPolicy
|
||||
static box LowerReturnMethodArrayMapBox {
|
||||
try_lower(program_json) {
|
||||
local s = "" + program_json
|
||||
local k_ret = s.indexOf("\"type\":\"Return\""); if k_ret < 0 { return null }
|
||||
local k_m = s.indexOf("\"type\":\"Method\"", k_ret); if k_m < 0 { return null }
|
||||
local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0); if k_ret < 0 { return null }
|
||||
local k_m = JsonFragBox.index_of_from(s, "\"type\":\"Method\"", k_ret); if k_m < 0 { return null }
|
||||
// receiver must be Var(name)
|
||||
local k_recv = s.indexOf("\"recv\":{\"type\":\"Var\"", k_m); if k_recv < 0 { return null }
|
||||
local k_recv = JsonFragBox.index_of_from(s, "\"recv\":{\"type\":\"Var\"", k_m); if k_recv < 0 { return null }
|
||||
local method = null
|
||||
{ local km = s.indexOf("\"method\":\"", k_m); if km < 0 { return null } method = JsonFragBox.read_string_after(s, km) }
|
||||
{ local km = JsonFragBox.index_of_from(s, "\"method\":\"", k_m); if km < 0 { return null } method = JsonFragBox.read_string_after(s, km) }
|
||||
// Standardize: generate 'size' (len/length are accepted aliases at receiver)
|
||||
method = MethodAliasPolicy.normalize_size(method)
|
||||
// Allow basic methods
|
||||
@ -23,91 +23,56 @@ static box LowerReturnMethodArrayMapBox {
|
||||
local b0 = new ArrayBox()
|
||||
// Receiver placeholder (Var resolve未実装のため 0 を置く)
|
||||
b0.push(MirSchemaBox.inst_const(1, 0))
|
||||
local k_args = s.indexOf("\"args\":", k_m)
|
||||
local k_args = JsonFragBox.index_of_from(s, "\"args\":", k_m)
|
||||
local next_id = 2
|
||||
if k_args >= 0 {
|
||||
// first arg: Int or Var(Int)
|
||||
local k_i1 = s.indexOf("\"type\":\"Int\"", k_args)
|
||||
local k_v1 = s.indexOf("\"type\":\"Var\"", k_args)
|
||||
local k_i1 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_args)
|
||||
local k_v1 = JsonFragBox.index_of_from(s, "\"type\":\"Var\"", k_args)
|
||||
if k_i1 >= 0 && (k_v1 < 0 || k_i1 < k_v1) {
|
||||
// read numeric after value:
|
||||
local k_val1 = s.indexOf("\"value\":", k_i1)
|
||||
local k_val1 = JsonFragBox.index_of_from(s, "\"value\":", k_i1)
|
||||
if k_val1 >= 0 {
|
||||
local v1 = JsonFragBox.read_int_after(s, k_val1 + 8)
|
||||
if v1 != null { b0.push(MirSchemaBox.inst_const(next_id, v1)) args_ids.push(next_id) next_id = next_id + 1 }
|
||||
}
|
||||
// second arg after first
|
||||
local k_i2 = s.indexOf("\"type\":\"Int\"", k_i1 + 1)
|
||||
local k_v2a = s.indexOf("\"type\":\"Var\"", k_i1 + 1)
|
||||
local k_i2 = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_i1 + 1)
|
||||
local k_v2a = JsonFragBox.index_of_from(s, "\"type\":\"Var\"", k_i1 + 1)
|
||||
if k_i2 >= 0 {
|
||||
local k_v2 = s.indexOf("\"value\":", k_i2)
|
||||
local k_v2 = JsonFragBox.index_of_from(s, "\"value\":", k_i2)
|
||||
if k_v2 >= 0 { local v2 = JsonFragBox.read_int_after(s, k_v2 + 8); if v2 != null { b0.push(MirSchemaBox.inst_const(next_id, v2)) args_ids.push(next_id) next_id = next_id + 1 } }
|
||||
} else if k_v2a >= 0 {
|
||||
// second arg is Var: resolve Local Int value
|
||||
local kn = s.indexOf("\"name\":\"", k_v2a)
|
||||
local kn = JsonFragBox.index_of_from(s, "\"name\":\"", k_v2a)
|
||||
if kn >= 0 {
|
||||
local name2 = JsonFragBox.read_string_after(s, kn)
|
||||
// scan backwards for Local name2 Int
|
||||
local pos = 0; local last = -1
|
||||
loop(true) {
|
||||
local kL = s.indexOf("\"type\":\"Local\"", pos)
|
||||
if kL < 0 || kL >= k_m { break }
|
||||
local nm = null
|
||||
{
|
||||
local kn2 = s.indexOf("\"name\":\"", kL)
|
||||
if kn2 >= 0 {
|
||||
local iii = kn2 + 8; local nnn = s.length(); local jjj = iii
|
||||
loop(jjj < nnn) { if s.substring(jjj,jjj+1) == '"' { break } jjj = jjj + 1 }
|
||||
nm = s.substring(iii, jjj)
|
||||
}
|
||||
}
|
||||
if nm != null && nm == name2 { last = kL }
|
||||
pos = kL + 1
|
||||
}
|
||||
if last >= 0 {
|
||||
local ki = s.indexOf("\"type\":\"Int\"", last)
|
||||
if ki >= 0 && ki < k_m {
|
||||
local kv = s.indexOf("\"value\":", ki)
|
||||
if kv >= 0 { local v = JsonFragBox.read_int_after(s, kv + 8); if v != null { b0.push(MirSchemaBox.inst_const(next_id, v)) args_ids.push(next_id) next_id = next_id + 1 } }
|
||||
}
|
||||
}
|
||||
local v = PatternUtilBox.find_local_int_before(s, name2, k_m)
|
||||
if v != null { b0.push(MirSchemaBox.inst_const(next_id, v)) args_ids.push(next_id) next_id = next_id + 1 }
|
||||
}
|
||||
}
|
||||
} else if k_v1 >= 0 && (k_i1 < 0 || k_v1 < k_i1) {
|
||||
// first arg is Var: resolve Local value (Int/Bool/Float/String)
|
||||
local kn = s.indexOf("\"name\":\"", k_v1)
|
||||
local kn = JsonFragBox.index_of_from(s, "\"name\":\"", k_v1)
|
||||
if kn >= 0 {
|
||||
local namev = JsonFragBox.read_string_after(s, kn)
|
||||
// find last Local namev Int before method
|
||||
local pos2 = 0; local last2 = -1
|
||||
loop(true) {
|
||||
local kL2 = s.indexOf("\"type\":\"Local\"", pos2)
|
||||
if kL2 < 0 || kL2 >= k_m { break }
|
||||
local nm2 = null
|
||||
// Prefer exact-name Local lookups via PatternUtilBox
|
||||
// Int / Bool / Float / String (in this order)
|
||||
{
|
||||
local knm = s.indexOf("\"name\":\"", kL2)
|
||||
if knm >= 0 {
|
||||
local iii2 = knm + 8; local nnn2 = s.length(); local jjj2 = iii2
|
||||
loop(jjj2 < nnn2) { if s.substring(jjj2,jjj2+1) == '"' { break } jjj2 = jjj2 + 1 }
|
||||
nm2 = s.substring(iii2, jjj2)
|
||||
local vi = PatternUtilBox.find_local_int_before(s, namev, k_m)
|
||||
if vi != null { b0.push(MirSchemaBox.inst_const(next_id, vi)) args_ids.push(next_id) next_id = next_id + 1 }
|
||||
}
|
||||
{
|
||||
local vb = PatternUtilBox.find_local_bool_before(s, namev, k_m)
|
||||
if vb != null { b0.push(MirSchemaBox.inst_const(next_id, vb)) args_ids.push(next_id) next_id = next_id + 1 }
|
||||
}
|
||||
if nm2 != null && nm2 == namev { last2 = kL2 }
|
||||
pos2 = kL2 + 1
|
||||
{
|
||||
local vf = PatternUtilBox.find_local_float_before(s, namev, k_m)
|
||||
if vf != null { b0.push(MirSchemaBox.inst_const_f64(next_id, vf)) args_ids.push(next_id) next_id = next_id + 1 }
|
||||
}
|
||||
if last2 >= 0 {
|
||||
// Int
|
||||
local ki3 = s.indexOf("\"type\":\"Int\"", last2)
|
||||
if ki3 >= 0 && ki3 < k_m { local kv3 = s.indexOf("\"value\":", ki3); if kv3 >= 0 { local v = JsonFragBox.read_int_after(s, kv3 + 8); if v != null { b0.push(MirSchemaBox.inst_const(next_id, v)) args_ids.push(next_id) next_id = next_id + 1 } } }
|
||||
// Bool
|
||||
local kb3 = s.indexOf("\"type\":\"Bool\"", last2)
|
||||
if kb3 >= 0 && kb3 < k_m { local kvb = s.indexOf("\"value\":", kb3); if kvb >= 0 { local vb = JsonFragBox.read_bool_after(s, kvb + 8); if vb != null { b0.push(MirSchemaBox.inst_const(next_id, vb)) args_ids.push(next_id) next_id = next_id + 1 } } }
|
||||
// Float
|
||||
local kf3 = s.indexOf("\"type\":\"Float\"", last2)
|
||||
if kf3 >= 0 && kf3 < k_m { local kvf = s.indexOf("\"value\":", kf3); if kvf >= 0 { local fv = JsonFragBox.read_float_after(s, kvf + 8); if fv != null { b0.push(MirSchemaBox.inst_const_f64(next_id, fv)) args_ids.push(next_id) next_id = next_id + 1 } } }
|
||||
// String
|
||||
local ks3 = s.indexOf("\"type\":\"String\"", last2)
|
||||
if ks3 >= 0 && ks3 < k_m { local kvs = s.indexOf("\"value\":\"", ks3); if kvs >= 0 { local sv = JsonFragBox.read_string_after(s, kvs + 8); if sv != null { b0.push(MirSchemaBox.inst_const_str(next_id, sv)) args_ids.push(next_id) next_id = next_id + 1 } } }
|
||||
{
|
||||
local vs = PatternUtilBox.find_local_string_before(s, namev, k_m)
|
||||
if vs != null { b0.push(MirSchemaBox.inst_const_str(next_id, vs)) args_ids.push(next_id) next_id = next_id + 1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,11 +6,11 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
static box LowerReturnStringBox {
|
||||
try_lower(program_json) {
|
||||
local s = "" + program_json
|
||||
local k_ret = s.indexOf("\"type\":\"Return\"")
|
||||
local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0)
|
||||
if k_ret < 0 { return null }
|
||||
local k_str = s.indexOf("\"type\":\"String\"", k_ret)
|
||||
local k_str = JsonFragBox.index_of_from(s, "\"type\":\"String\"", k_ret)
|
||||
if k_str < 0 { return null }
|
||||
local k_val = s.indexOf("\"value\":", k_str)
|
||||
local k_val = JsonFragBox.index_of_from(s, "\"value\":", k_str)
|
||||
if k_val < 0 { return null }
|
||||
local sval = JsonFragBox.read_string_after(s, k_val+8)
|
||||
if sval == null { return null }
|
||||
|
||||
@ -7,25 +7,25 @@ static box LowerReturnVarLocalBox {
|
||||
try_lower(program_json) {
|
||||
local s = "" + program_json
|
||||
// Find Local with name:"x" and expr Int value
|
||||
local k_loc = s.indexOf("\"type\":\"Local\"")
|
||||
local k_loc = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", 0)
|
||||
if k_loc < 0 { return null }
|
||||
// Extract name
|
||||
local k_name = s.indexOf("\"name\":", k_loc); if k_name < 0 { return null }
|
||||
local k_name = JsonFragBox.index_of_from(s, "\"name\":", k_loc); if k_name < 0 { return null }
|
||||
local name = JsonFragBox.read_string_after(s, k_name + 5)
|
||||
if name == null || name == "" { return null }
|
||||
// Ensure expr Int after this Local
|
||||
local k_int = s.indexOf("\"type\":\"Int\"", k_loc)
|
||||
local k_int = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", k_loc)
|
||||
if k_int < 0 { return null }
|
||||
local kv = s.indexOf("\"value\":", k_int); if kv < 0 { return null }
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", k_int); if kv < 0 { return null }
|
||||
local val = JsonFragBox.read_int_after(s, kv + 8)
|
||||
if val == null { return null }
|
||||
// Following Return Var(name)
|
||||
local k_ret = s.indexOf("\"type\":\"Return\"", k_loc)
|
||||
local k_ret = JsonFragBox.index_of_from(s, "\"type\":\"Return\"", k_loc)
|
||||
if k_ret < 0 { return null }
|
||||
// Verify Var(name)
|
||||
local k_var = s.indexOf("\"type\":\"Var\"", k_ret)
|
||||
local k_var = JsonFragBox.index_of_from(s, "\"type\":\"Var\"", k_ret)
|
||||
if k_var < 0 { return null }
|
||||
local k_vn = s.indexOf("\"name\":", k_var); if k_vn < 0 { return null }
|
||||
local k_vn = JsonFragBox.index_of_from(s, "\"name\":", k_var); if k_vn < 0 { return null }
|
||||
local vname = JsonFragBox.read_string_after(s, k_vn + 5)
|
||||
if vname == null || vname != name { return null }
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ using selfhost.shared.common.string_helpers as StringHelpers
|
||||
|
||||
static box PatternUtilBox {
|
||||
map_cmp(sym) { if sym=="<" {return "Lt"} if sym==">" {return "Gt"} if sym=="<=" {return "Le"} if sym==">=" {return "Ge"} if sym=="==" {return "Eq"} if sym=="!=" {return "Ne"} return null }
|
||||
map_binop(sym) { if sym=="+" {return "Add"} if sym=="-" {return "Sub"} if sym=="*" {return "Mul"} if sym=="/" {return "Div"} return null }
|
||||
// Normalize (op, swapped, limit) → (cmp, limit') where cmp in {Lt, Le, Gt, Ge}
|
||||
// swapped=0: i ? L, swapped=1: L ? i
|
||||
normalize_cmp_limit(op, swapped, limit_str) {
|
||||
@ -50,9 +51,9 @@ static box PatternUtilBox {
|
||||
// Bound the search between this Local and the next Local/before_pos
|
||||
local next = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last + 1)
|
||||
if next < 0 || next > before_pos { next = before_pos }
|
||||
local ki = s.indexOf("\"type\":\"Int\"", last)
|
||||
local ki = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", last)
|
||||
if ki < 0 || ki >= next { return null }
|
||||
local kv = s.indexOf("\"value\":", ki)
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", ki)
|
||||
if kv < 0 || kv >= next { return null }
|
||||
return JsonFragBox.read_int_after(s, kv+8)
|
||||
}
|
||||
@ -62,14 +63,64 @@ static box PatternUtilBox {
|
||||
if last<0 { return null }
|
||||
local next = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last + 1)
|
||||
if next < 0 || next > before_pos { next = before_pos }
|
||||
local kb = s.indexOf("\"type\":\"Bool\"", last)
|
||||
local kb = JsonFragBox.index_of_from(s, "\"type\":\"Bool\"", last)
|
||||
if kb < 0 || kb >= next { return null }
|
||||
local kv = s.indexOf("\"value\":", kb)
|
||||
local kv = JsonFragBox.index_of_from(s, "\"value\":", kb)
|
||||
if kv < 0 || kv >= next { return null }
|
||||
// JSON v0 uses 0/1 for bool values, not true/false literals
|
||||
return JsonFragBox.read_int_after(s, kv+8)
|
||||
}
|
||||
|
||||
// Find the last Local(String) with given name before a given position.
|
||||
// Returns raw string or null when not found.
|
||||
find_local_string_before(s, name, before_pos) {
|
||||
local pos=0; local last=-1
|
||||
loop(true){
|
||||
local k=JsonFragBox.index_of_from(s, "\"type\":\"Local\"",pos)
|
||||
if k<0||k>=before_pos{break}
|
||||
local kn=JsonFragBox.index_of_from(s, "\"name\":\"",k)
|
||||
if kn>=0{
|
||||
local ii=kn+8; local nn=(""+s).length(); local jj=ii
|
||||
loop(jj<nn){ if (""+s).substring(jj,jj+1)=="\"" {break} jj=jj+1 }
|
||||
if (""+s).substring(ii,jj)==name { last=k }
|
||||
}
|
||||
pos=k+1
|
||||
}
|
||||
if last<0 { return null }
|
||||
local next=JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last+1)
|
||||
if next<0||next>before_pos{ next=before_pos }
|
||||
local ts=(""+s).indexOf("\"type\":\"String\"", last)
|
||||
if ts<0||ts>=next { return null }
|
||||
local kv=(""+s).indexOf("\"value\":\"", ts)
|
||||
if kv<0||kv>=next { return null }
|
||||
return JsonFragBox.read_string_after(s, kv+8)
|
||||
}
|
||||
|
||||
// Find the last Local(Float) with given name before a given position.
|
||||
// Returns float string (as scanned) or null when not found.
|
||||
find_local_float_before(s, name, before_pos) {
|
||||
local pos=0; local last=-1
|
||||
loop(true){
|
||||
local k=JsonFragBox.index_of_from(s, "\"type\":\"Local\"",pos)
|
||||
if k<0||k>=before_pos{break}
|
||||
local kn=JsonFragBox.index_of_from(s, "\"name\":\"",k)
|
||||
if kn>=0{
|
||||
local ii=kn+8; local nn=(""+s).length(); local jj=ii
|
||||
loop(jj<nn){ if (""+s).substring(jj,jj+1)=="\"" {break} jj=jj+1 }
|
||||
if (""+s).substring(ii,jj)==name { last=k }
|
||||
}
|
||||
pos=k+1
|
||||
}
|
||||
if last<0 { return null }
|
||||
local next=JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last+1)
|
||||
if next<0||next>before_pos{ next=before_pos }
|
||||
local tf=(""+s).indexOf("\"type\":\"Float\"", last)
|
||||
if tf<0||tf>=next { return null }
|
||||
local kv=(""+s).indexOf("\"value\":", tf)
|
||||
if kv<0||kv>=next { return null }
|
||||
return JsonFragBox.read_float_after(s, kv+8)
|
||||
}
|
||||
|
||||
// Find the last Local(Int) before a given position (name-agnostic).
|
||||
// Returns string digits or null when not found.
|
||||
find_any_local_int_before(s, before_pos) {
|
||||
|
||||
@ -33,9 +33,12 @@ impl NyashEnv {
|
||||
|
||||
// Global current env config (thread-safe)
|
||||
use once_cell::sync::OnceCell;
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::RwLock;
|
||||
|
||||
static GLOBAL_ENV: OnceCell<RwLock<NyashEnv>> = OnceCell::new();
|
||||
static WARNED_ALIASES: OnceCell<Mutex<HashSet<String>>> = OnceCell::new();
|
||||
// フェーズM.2: PHI_ON_GATED_WARNED削除(phi-legacy簡略化により不要)
|
||||
|
||||
pub fn current() -> NyashEnv {
|
||||
@ -376,11 +379,19 @@ pub fn cli_verbose() -> bool {
|
||||
}
|
||||
pub fn enable_using() -> bool {
|
||||
// Phase 15: デフォルトON(using systemはメイン機能)
|
||||
// NYASH_ENABLE_USING=0 で明示的に無効化可能
|
||||
// NYASH_ENABLE_USING=0 で明示的に無効化可能。HAKO_ENABLE_USING は互換のため受理(警告)。
|
||||
match std::env::var("NYASH_ENABLE_USING").ok().as_deref() {
|
||||
Some("0") | Some("false") | Some("off") => false,
|
||||
_ => true, // デフォルト: ON
|
||||
Some("0") | Some("false") | Some("off") => return false,
|
||||
Some(_) => return true,
|
||||
None => {}
|
||||
}
|
||||
// Fallback to alias
|
||||
if let Some(v) = std::env::var("HAKO_ENABLE_USING").ok() {
|
||||
warn_alias_once("HAKO_ENABLE_USING", "NYASH_ENABLE_USING");
|
||||
let lv = v.to_ascii_lowercase();
|
||||
return !(lv == "0" || lv == "false" || lv == "off");
|
||||
}
|
||||
true // default ON
|
||||
}
|
||||
|
||||
// ---- Using profiles (dev|ci|prod) ----
|
||||
@ -466,7 +477,14 @@ pub fn ny_compiler_stage3() -> bool {
|
||||
/// When enabled, the Rust parser accepts Stage-3 surface (try/catch/finally, throw).
|
||||
/// Default is OFF to keep Stage-2 stable.
|
||||
pub fn parser_stage3() -> bool {
|
||||
std::env::var("NYASH_PARSER_STAGE3").ok().as_deref() == Some("1")
|
||||
if std::env::var("NYASH_PARSER_STAGE3").ok().as_deref() == Some("1") {
|
||||
return true;
|
||||
}
|
||||
if std::env::var("HAKO_PARSER_STAGE3").ok().as_deref() == Some("1") {
|
||||
warn_alias_once("HAKO_PARSER_STAGE3", "NYASH_PARSER_STAGE3");
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Parser gate for Block‑Postfix Catch acceptance
|
||||
@ -578,3 +596,72 @@ pub fn oob_strict_fail() -> bool {
|
||||
.or_else(|| env_flag("NYASH_OOB_STRICT_FAIL"))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Primary verification route: return true when Hakorune VM is requested as primary.
|
||||
/// Accepts HAKO_VERIFY_PRIMARY=hakovm (preferred) or legacy HAKO_ROUTE_HAKOVM=1 (deprecated, warns).
|
||||
pub fn verify_primary_is_hakovm() -> bool {
|
||||
if std::env::var("HAKO_VERIFY_PRIMARY").ok().as_deref() == Some("hakovm") {
|
||||
return true;
|
||||
}
|
||||
if env_bool("HAKO_ROUTE_HAKOVM") {
|
||||
warn_alias_once("HAKO_ROUTE_HAKOVM", "HAKO_VERIFY_PRIMARY=hakovm");
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn warn_alias_once(alias: &str, primary: &str) {
|
||||
let set = WARNED_ALIASES.get_or_init(|| Mutex::new(HashSet::new()));
|
||||
if let Ok(mut s) = set.lock() {
|
||||
if !s.contains(alias) {
|
||||
eprintln!("[deprecate/env] '{}' is deprecated; use '{}'", alias, primary);
|
||||
s.insert(alias.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---- ENV consolidation helpers (Phase 21.10/22.1) ----
|
||||
/// LLVM opt level (primary: NYASH_LLVM_OPT_LEVEL; alias: HAKO_LLVM_OPT_LEVEL)
|
||||
/// Returns string level (e.g., "0", "1", ...). Default: "0" when unset.
|
||||
pub fn llvm_opt_level() -> String {
|
||||
if let Some(v) = std::env::var("NYASH_LLVM_OPT_LEVEL").ok() {
|
||||
return v;
|
||||
}
|
||||
if let Some(v) = std::env::var("HAKO_LLVM_OPT_LEVEL").ok() {
|
||||
warn_alias_once("HAKO_LLVM_OPT_LEVEL", "NYASH_LLVM_OPT_LEVEL");
|
||||
return v;
|
||||
}
|
||||
"0".to_string()
|
||||
}
|
||||
|
||||
/// Gate‑C(Core) route request (primary: NYASH_GATE_C_CORE; alias: HAKO_GATE_C_CORE)
|
||||
pub fn gate_c_core() -> bool {
|
||||
if env_bool("NYASH_GATE_C_CORE") { return true; }
|
||||
if env_bool("HAKO_GATE_C_CORE") {
|
||||
warn_alias_once("HAKO_GATE_C_CORE", "NYASH_GATE_C_CORE");
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Consolidated toggle for selfhost NY compiler pipeline.
|
||||
/// Primary: NYASH_USE_NY_COMPILER=0|1. Legacy disables accepted (with warning):
|
||||
/// NYASH_DISABLE_NY_COMPILER/HAKO_DISABLE_NY_COMPILER (any true value disables).
|
||||
pub fn use_ny_compiler() -> bool {
|
||||
// Primary knob takes precedence when explicitly set
|
||||
if let Some(v) = std::env::var("NYASH_USE_NY_COMPILER").ok() {
|
||||
let lv = v.trim().to_ascii_lowercase();
|
||||
return lv == "1" || lv == "true" || lv == "on";
|
||||
}
|
||||
// Legacy disable aliases — if any is true, treat as disabled and warn
|
||||
if env_bool("NYASH_DISABLE_NY_COMPILER") {
|
||||
warn_alias_once("NYASH_DISABLE_NY_COMPILER", "NYASH_USE_NY_COMPILER=0");
|
||||
return false;
|
||||
}
|
||||
if env_bool("HAKO_DISABLE_NY_COMPILER") {
|
||||
warn_alias_once("HAKO_DISABLE_NY_COMPILER", "NYASH_USE_NY_COMPILER=0");
|
||||
return false;
|
||||
}
|
||||
// Default: ON (MVP selfhost path)
|
||||
true
|
||||
}
|
||||
|
||||
@ -24,8 +24,8 @@ def lower_function(builder, func_data: Dict[str, Any]):
|
||||
|
||||
# Determine function signature
|
||||
if name == "ny_main":
|
||||
# Special case: ny_main returns i32
|
||||
func_ty = ir.FunctionType(builder.i32, [])
|
||||
# Special case: ny_main returns i64 to match runtime (nyrt) expectations
|
||||
func_ty = ir.FunctionType(builder.i64, [])
|
||||
else:
|
||||
# Default: i64(i64, ...) signature; derive arity from '/N' suffix when params missing
|
||||
m = re.search(r"/(\d+)$", name)
|
||||
|
||||
@ -45,6 +45,22 @@ def lower_binop(
|
||||
lhs_val = ir.Constant(ir.IntType(64), 0)
|
||||
if rhs_val is None:
|
||||
rhs_val = ir.Constant(ir.IntType(64), 0)
|
||||
# Normalize operation aliases (textual -> symbolic)
|
||||
op_raw = op or ''
|
||||
op_l = op_raw.lower()
|
||||
alias = {
|
||||
'add': '+', 'plus': '+',
|
||||
'sub': '-', 'minus': '-',
|
||||
'mul': '*', 'times': '*',
|
||||
'div': '/',
|
||||
'mod': '%', 'rem': '%',
|
||||
'band': '&', 'bitand': '&',
|
||||
'bor': '|', 'bitor': '|',
|
||||
'bxor': '^', 'xor': '^',
|
||||
'shl': '<<',
|
||||
'shr': '>>', 'ashr': '>>',
|
||||
}
|
||||
op = alias.get(op_l, op_raw)
|
||||
|
||||
# Relational/equality operators delegate to compare
|
||||
if op in ('==','!=','<','>','<=','>='):
|
||||
|
||||
@ -97,9 +97,16 @@ def lower_return(
|
||||
# Pointer type - null
|
||||
ret_val = ir.Constant(return_type, None)
|
||||
|
||||
# If still zero-like and we have predecessor snapshots, synthesize a minimal PHI at block head.
|
||||
# If still zero-like (typed zero) and we have predecessor snapshots, synthesize a minimal PHI at block head.
|
||||
try:
|
||||
zero_like = isinstance(ret_val, ir.Constant)
|
||||
zero_like = False
|
||||
if isinstance(ret_val, ir.Constant):
|
||||
if isinstance(return_type, ir.IntType):
|
||||
zero_like = (str(ret_val) == str(ir.Constant(return_type, 0)))
|
||||
elif isinstance(return_type, ir.DoubleType):
|
||||
zero_like = (str(ret_val) == str(ir.Constant(return_type, 0.0)))
|
||||
elif isinstance(return_type, ir.PointerType):
|
||||
zero_like = (str(ret_val) == str(ir.Constant(return_type, None)))
|
||||
if zero_like and preds is not None and block_end_values is not None and bb_map is not None and isinstance(value_id, int):
|
||||
# Derive current block id from name like 'bb3'
|
||||
cur_bid = None
|
||||
|
||||
@ -152,7 +152,8 @@ class NyashLLVMBuilder:
|
||||
else:
|
||||
arity = int(m.group(1)) if m else len(params_list)
|
||||
if name == "ny_main":
|
||||
fty = ir.FunctionType(self.i32, [])
|
||||
# Align with runtime expectation: ny_main returns i64
|
||||
fty = ir.FunctionType(self.i64, [])
|
||||
else:
|
||||
fty = ir.FunctionType(self.i64, [self.i64] * arity)
|
||||
exists = False
|
||||
|
||||
@ -13,8 +13,7 @@ fn main() {
|
||||
// If NYASH_VERIFY_JSON is present and route is requested, execute and exit.
|
||||
// This avoids plugin host/registry initialization and keeps output minimal.
|
||||
let has_json = std::env::var("NYASH_VERIFY_JSON").is_ok();
|
||||
let route = nyash_rust::config::env::env_bool("HAKO_ROUTE_HAKOVM")
|
||||
|| std::env::var("HAKO_VERIFY_PRIMARY").ok().as_deref() == Some("hakovm");
|
||||
let route = nyash_rust::config::env::verify_primary_is_hakovm();
|
||||
// Force flag may allow hv1-inline without route
|
||||
let force_hv1_flag = nyash_rust::config::env::env_bool("HAKO_VERIFY_V1_FORCE_HAKOVM");
|
||||
if has_json && (route || force_hv1_flag) {
|
||||
|
||||
@ -12,30 +12,9 @@ pub(crate) fn execute_file_with_backend(runner: &NyashRunner, filename: &str) {
|
||||
// Note: hv1 direct route is now handled at main.rs entry point (before NyashRunner creation).
|
||||
// This function is only called after plugins and runner initialization have already occurred.
|
||||
|
||||
// Selfhost pipeline (Ny -> JSON v0)
|
||||
// Default: ON. Backward‑compat envs:
|
||||
// - NYASH_USE_NY_COMPILER={1|true|on} to force ON
|
||||
// - NYASH_USE_NY_COMPILER={0|false|off} or NYASH_DISABLE_NY_COMPILER/HAKO_DISABLE_NY_COMPILER to disable
|
||||
let mut use_selfhost = true;
|
||||
if let Ok(v) = std::env::var("NYASH_USE_NY_COMPILER") {
|
||||
let lv = v.trim().to_ascii_lowercase();
|
||||
use_selfhost = matches!(lv.as_str(), "1" | "true" | "on");
|
||||
}
|
||||
let disabled = std::env::var("NYASH_DISABLE_NY_COMPILER")
|
||||
.ok()
|
||||
.map(|v| {
|
||||
let lv = v.trim().to_ascii_lowercase();
|
||||
matches!(lv.as_str(), "1" | "true" | "on")
|
||||
})
|
||||
.unwrap_or(false)
|
||||
|| std::env::var("HAKO_DISABLE_NY_COMPILER")
|
||||
.ok()
|
||||
.map(|v| {
|
||||
let lv = v.trim().to_ascii_lowercase();
|
||||
matches!(lv.as_str(), "1" | "true" | "on")
|
||||
})
|
||||
.unwrap_or(false);
|
||||
if use_selfhost && !disabled {
|
||||
// Selfhost pipeline (Ny -> JSON v0) — consolidated env toggle
|
||||
// Primary: NYASH_USE_NY_COMPILER=0|1; legacy disables accepted with deprecation warning
|
||||
if crate::config::env::use_ny_compiler() {
|
||||
if runner.try_run_selfhost_pipeline(filename) {
|
||||
return;
|
||||
} else {
|
||||
|
||||
241
tools/native_llvm_builder.py
Normal file
241
tools/native_llvm_builder.py
Normal 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)
|
||||
@ -24,7 +24,17 @@ TARGET=""
|
||||
NYRT_DIR=""
|
||||
VERIFY=0
|
||||
QUIET=0
|
||||
BACKEND="${NYASH_LLVM_BACKEND:-llvmlite}" # llvmlite | crate | native (reserved)
|
||||
# Backend selection (21.11): default to 'crate' when ny-llvmc is available, otherwise fallback to llvmlite.
|
||||
# Explicit env NYASH_LLVM_BACKEND overrides this auto-detection.
|
||||
if [[ -n "${NYASH_LLVM_BACKEND:-}" ]]; then
|
||||
BACKEND="${NYASH_LLVM_BACKEND}"
|
||||
else
|
||||
if [[ -x "./target/release/ny-llvmc" ]]; then
|
||||
BACKEND="crate"
|
||||
else
|
||||
BACKEND="llvmlite"
|
||||
fi
|
||||
fi
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
@ -51,10 +61,13 @@ if [[ -z "$OUT" ]]; then
|
||||
esac
|
||||
fi
|
||||
|
||||
# Require LLVM18 only for llvmlite backend
|
||||
if [[ "${NYASH_LLVM_BACKEND:-$BACKEND}" == "llvmlite" ]]; then
|
||||
if ! command -v llvm-config-18 >/dev/null 2>&1; then
|
||||
echo "error: llvm-config-18 not found (install LLVM 18 dev)" >&2
|
||||
exit 3
|
||||
fi
|
||||
fi
|
||||
|
||||
# Build nyash + NyRT as needed(skip allowed)
|
||||
LLVM_FEATURE=${NYASH_LLVM_FEATURE:-llvm}
|
||||
@ -126,6 +139,15 @@ case "$EMIT" in
|
||||
rm -f "$OUT"
|
||||
"$BIN_NYLLVMC" --in "$IN_FILE" --emit obj --out "$OUT" >/dev/null 2>&1 || { echo "error: ny-llvmc failed" >&2; exit 4; }
|
||||
;;
|
||||
native)
|
||||
if ! command -v llc >/dev/null 2>&1; then
|
||||
echo "error: llc not found (install LLVM tools)" >&2; exit 4
|
||||
fi
|
||||
rm -f "$OUT"
|
||||
if ! python3 "$PWD/tools/native_llvm_builder.py" --in "$IN_FILE" --emit obj --out "$OUT" >/dev/null 2>&1; then
|
||||
echo "error: native builder failed" >&2; exit 4
|
||||
fi
|
||||
;;
|
||||
llvmlite|*)
|
||||
# Directly use llvmlite harness with MIR v1 JSON input
|
||||
rm -f "$OUT"
|
||||
@ -153,6 +175,22 @@ case "$EMIT" in
|
||||
echo "error: ny-llvmc failed to link exe" >&2; exit 4
|
||||
fi
|
||||
;;
|
||||
native)
|
||||
if ! command -v llc >/dev/null 2>&1; then
|
||||
echo "error: llc not found (install LLVM tools)" >&2; exit 4
|
||||
fi
|
||||
if ! python3 "$PWD/tools/native_llvm_builder.py" --in "$IN_FILE" --emit obj --out "$OBJ" >/dev/null 2>&1; then
|
||||
echo "error: native builder failed to produce object $OBJ" >&2; exit 4
|
||||
fi
|
||||
if [[ ! -f "$OBJ" ]]; then echo "error: failed to produce object $OBJ" >&2; exit 4; fi
|
||||
# Link with NyRT (same as llvmlite branch)
|
||||
NYRT_BASE=${NYRT_DIR:-"$PWD/crates/nyash_kernel"}
|
||||
cc "$OBJ" \
|
||||
-L target/release \
|
||||
-L "$NYRT_BASE/target/release" \
|
||||
-Wl,--whole-archive -lnyash_kernel -Wl,--no-whole-archive \
|
||||
-lpthread -ldl -lm -o "$OUT"
|
||||
;;
|
||||
llvmlite|*)
|
||||
if ! python3 "$PWD/tools/llvmlite_harness.py" --in "$IN_FILE" --out "$OBJ" >/dev/null 2>&1; then
|
||||
echo "error: harness failed to produce object $OBJ" >&2; exit 4
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -64,4 +64,34 @@ if [[ "${SMOKES_ENABLE_SELFHOST:-0}" == "1" ]]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# Crate backend (ny-llvmc) — run a tiny representative set always when available
|
||||
echo "[phase2100] S3 (crate ny-llvmc) reps..."
|
||||
(
|
||||
set -e
|
||||
# Prebuild crate tools quickly (best-effort)
|
||||
(cd "$ROOT/crates/nyash-llvm-compiler" && timeout 180 cargo build --release -j 24 >/dev/null 2>&1) || true
|
||||
(cd "$ROOT/crates/nyash_kernel" && timeout 180 cargo build --release -j 24 >/dev/null 2>&1) || true
|
||||
# Probe ny-llvmc availability by compiling a minimal ret0 ny_main
|
||||
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
||||
if [[ -x "$BIN_NYLLVMC" ]]; then
|
||||
tmpj="/tmp/ny_crate_probe_$$.json"; echo '{"schema_version":1,"functions":[{"name":"ny_main","blocks":[{"id":0,"inst":[{"op":"const","dst":1,"ty":"i64","value":0},{"op":"ret","value":1}]}]}]}' > "$tmpj"
|
||||
tmpo="/tmp/ny_crate_probe_$$.o"
|
||||
if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$tmpj" --out "$tmpo" >/dev/null 2>&1; then
|
||||
rm -f "$tmpo" "$tmpj" || true
|
||||
# Run representative crate EXE canaries (fast)
|
||||
bash "$ROOT/tools/smokes/v2/run.sh" --profile quick --filter 'phase2100/s3_backend_selector_crate_exe_return42_canary_vm.sh'
|
||||
bash "$ROOT/tools/smokes/v2/run.sh" --profile quick --filter 'phase2100/s3_backend_selector_crate_exe_compare_eq_true_canary_vm.sh'
|
||||
bash "$ROOT/tools/smokes/v2/run.sh" --profile quick --filter 'phase2100/s3_backend_selector_crate_exe_binop_return_canary_vm.sh'
|
||||
else
|
||||
rm -f "$tmpo" "$tmpj" || true
|
||||
echo "[phase2100] SKIP crate reps (ny-llvmc probe failed)" >&2
|
||||
fi
|
||||
else
|
||||
echo "[phase2100] SKIP crate reps (ny-llvmc not built)" >&2
|
||||
fi
|
||||
) || echo "[phase2100] crate reps encountered a non-fatal issue; continuing"
|
||||
|
||||
# SSOT relative inference — unique case (always-on, quick)
|
||||
bash "$ROOT/tools/smokes/v2/run.sh" --profile quick --filter 'phase2211/ssot_relative_unique_canary_vm.sh'
|
||||
|
||||
echo "[phase2100] Done."
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -29,10 +29,10 @@ APP="/tmp/ny_crate_backend_exe_print_$$"
|
||||
TMP_JSON="/tmp/ny_crate_backend_exe_print_$$.json"
|
||||
echo "$JSON" > "$TMP_JSON"
|
||||
|
||||
LIBDIR_MIN="$ROOT/crates/nyash_kernel_min_c/target/release"
|
||||
LIBDIR_MIN="$ROOT/target/release"
|
||||
LIBS="-L $LIBDIR_MIN -lnyash_kernel_min_c"
|
||||
|
||||
if "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --libs "$LIBS" --out "$APP" >/dev/null 2>&1; then
|
||||
if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --libs="$LIBS" --out "$APP" >/dev/null 2>&1; then
|
||||
if [[ -x "$APP" ]]; then
|
||||
set +e
|
||||
out="$($APP 2>/dev/null)"; rc=$?
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user