Phase 22.1 WIP: SSOT resolver + TLV infrastructure + Hako MIR builder setup
Setup infrastructure for Phase 22.1 (TLV C shim & Resolver SSOT):
Core changes:
- Add nyash_tlv, nyash_c_core, nyash_kernel_min_c crates (opt-in)
- Implement SSOT resolver bridge (src/using/ssot_bridge.rs)
- Add HAKO_USING_SSOT=1 / HAKO_USING_SSOT_HAKO=1 env support
- Add HAKO_TLV_SHIM=1 infrastructure (requires --features tlv-shim)
MIR builder improvements:
- Fix using/alias consistency in Hako MIR builder
- Add hako.mir.builder.internal.{prog_scan,pattern_util} to nyash.toml
- Normalize LLVM extern calls: nyash.console.* → nyash_console_*
Smoke tests:
- Add phase2211 tests (using_ssot_hako_parity_canary_vm.sh)
- Add phase2220, phase2230, phase2231 test structure
- Add phase2100 S3 backend selector tests
- Improve test_runner.sh with quiet/timeout controls
Documentation:
- Add docs/ENV_VARS.md (Phase 22.1 env vars reference)
- Add docs/development/runtime/C_CORE_ABI.md
- Update de-rust-roadmap.md with Phase 22.x details
Tools:
- Add tools/hakorune_emit_mir.sh (Hako-first MIR emission wrapper)
- Add tools/tlv_roundtrip_smoke.sh placeholder
- Improve ny_mir_builder.sh with better backend selection
Known issues (to be fixed):
- Parser infinite loop in static method parameter parsing
- Stage-B output contamination with "RC: 0" (needs NYASH_JSON_ONLY=1)
- phase2211/using_ssot_hako_parity_canary_vm.sh fork bomb (needs recursion guard)
Next steps: Fix parser infinite loop + Stage-B quiet mode for green tests
This commit is contained in:
100
CURRENT_TASK.md
100
CURRENT_TASK.md
@ -20,12 +20,84 @@ Update (today)
|
||||
- String API: size() を length() のエイリアスとして VM で受理
|
||||
- Analyzer CLI: --format/--debug/--source-file を順不同で処理
|
||||
- Analyzer IR: AST 空時の methods をテキスト走査でフォールバック
|
||||
- HC021/HC031: 実装完了。PHI 調査は一旦収束(AST path は既定OFF、`--force-ast` でオン)。
|
||||
- CLI: `--rules`/`--skip-rules` を追加し、ルール単体/組合せ検証を高速化。`--no-ast` 既定化。
|
||||
- Runtime: `NYASH_SCRIPT_ARGS_HEX_JSON` を導入(HEX経由で改行・特殊文字を安全搬送)。
|
||||
- File I/O: FileBox provider 設計(SSOT + 薄いラッパ + 選択ポリシー)を文書化(docs/development/runtime/FILEBOX_PROVIDER.md)。
|
||||
- HC021/HC031: 実装完了。PHI 調査は一旦収束(AST path は既定OFF、`--force-ast` でオン)。
|
||||
- CLI: `--rules`/`--skip-rules` を追加し、ルール単体/組合せ検証を高速化。`--no-ast` 既定化。
|
||||
- Runtime: `NYASH_SCRIPT_ARGS_HEX_JSON` を導入(HEX経由で改行・特殊文字を安全搬送)。
|
||||
- File I/O: FileBox provider 設計(SSOT + 薄いラッパ + 選択ポリシー)を文書化(docs/development/runtime/FILEBOX_PROVIDER.md)。
|
||||
- ENV: `NYASH_FILEBOX_MODE=auto|core-ro|plugin-only` を追加(ENV_VARS.md)。Analyzer/CI は core‑ro 相当で運用。
|
||||
|
||||
Quick update — Green Conditions & Toggles(quick)
|
||||
- Green baseline(quick)
|
||||
- Builder: Hako registry/internal = ON(既定)。必要時のみ `=0` でOFF。
|
||||
- hv1 inline PRIMARY = ON(直列も緑)。必要時のみ `HAKO_PHASE2100_ENABLE_HV1=0`。
|
||||
- S3 reps: 任意(`NYASH_LLVM_S3=1` かつ LLVM18 環境時)。未満は自動SKIP。
|
||||
- EXE‑first: 任意(`SMOKES_ENABLE_SELFHOST=1`)。重いのでデフォルトOFF。
|
||||
- TLV smoke: 常時(nyash-tlv のみを -p でビルド/テスト)。本体未配線でも安全。
|
||||
|
||||
Toggles quicklist
|
||||
- Builder: `HAKO_MIR_BUILDER_INTERNAL=0/1`(既定=1), `HAKO_MIR_BUILDER_REGISTRY=0/1`(既定=1)
|
||||
- hv1: `HAKO_PHASE2100_ENABLE_HV1=0/1`(既定=1)
|
||||
- S3: `NYASH_LLVM_S3=0/1`(既定=auto; LLVM18検出でON)
|
||||
- EXE‑first: `SMOKES_ENABLE_SELFHOST=1`(既定OFF)
|
||||
- TLV: `--features tlv-shim` + `HAKO_TLV_SHIM=1`(既定OFF/配線は無害な identity)
|
||||
- Using SSOT: `HAKO_USING_SSOT=1`(MVP は現行解決ロジックを経由しつつタグ出力)
|
||||
|
||||
22.1 progress (today)
|
||||
- TLV配線(最小導線・既定OFF)
|
||||
- 追加: ルート `Cargo.toml` に `nyash-tlv`(optional)と feature `tlv-shim`
|
||||
- 追加: `src/runtime/plugin_ffi_common.rs` に `maybe_tlv_roundtrip()` を実装し、`encode_args()` の末尾で呼び出し(ENV `HAKO_TLV_SHIM=1` かつ feature 有効時のみ動作)
|
||||
- スモーク: `tools/tlv_roundtrip_smoke.sh` を SKIP→常時 PASS に変更(`-p nyash-tlv` 固定)
|
||||
- Resolver/Using SSOT(薄い導線・トグル)
|
||||
- 追加: `HAKO_USING_SSOT=1` 時に SSOT ブリッジを呼び出し(modules のみを ctx として渡す)。未解決時は既存ロジックにフォールバック
|
||||
- ctx: `{ modules, using_paths, cwd }`(MVPは modules のみ有効)
|
||||
- トレース: `NYASH_RESOLVE_TRACE=1` で `[using/ssot]` タグを出力
|
||||
- スモーク: `tools/smokes/v2/profiles/quick/core/phase2211/using_ssot_parity_canary_vm.sh` を追加(ON/OFF で出力同一を検証)
|
||||
|
||||
22.1 next (follow‑up tasks)
|
||||
- SSOT ctx 拡張(段階導入・既定不変)
|
||||
- [ ] Bridge→Hako 箱で `using_paths`/`cwd` を活用した相対推定のMVP(IOはRunner側で制御)。
|
||||
- [ ] Runner 側の ctx 渡しを拡張し、パス推定に必要な情報(呼出元ディレクトリ、プロファイル)を追加。
|
||||
- 受け入れ: パリティcanary(modules命名あり)維持 + 代表ケースで `using_paths` 提示時に解決成功(既定OFF/トグルONのみ)。
|
||||
- TLV shim 観測タグ(既定OFF・安全)
|
||||
- [x] `HAKO_TLV_SHIM_TRACE=1` で shim 経由のコールに `[tlv/shim:<Box>.<method>]` を出力(既定は `MapBox.set` のみ)。
|
||||
- [x] `HAKO_TLV_SHIM_FILTER=MapBox.set` などで対象コールを限定(カンマ区切り可)。
|
||||
- 受け入れ: canary で `MapBox.set` の単発コール時にタグが現れる(feature有効+ENV時)、既定OFFではログ増加なし。
|
||||
|
||||
22.1 exit (criteria)
|
||||
- SSOT(relative 推定の仕上げ)
|
||||
- Unique: `phase2211/ssot_relative_unique_canary_vm.sh` が常時 PASS(cwd 優先、短時間で終了)。
|
||||
- Ambiguous+strict: `phase2211/ssot_relative_ambiguous_strict_canary_vm.sh` が PASS(strict=1 時は legacy 委譲)。
|
||||
- Recursion guard: `HAKO_USING_SSOT_HAKO=1` を含む実行でも無限再帰は発生しない(子プロセスへ SSOT を強制OFF+INVOKING=1)。
|
||||
- TLV/Extern(観測統合)
|
||||
- `HAKO_CALL_TRACE=1` で plugin/extern 双方に `[call:<target>.<method>]` が観測可能。
|
||||
- `HAKO_CALL_TRACE_FILTER` で method 名/`<target>.<method>` の双方が機能(例: `MapBox.set,env.console.log`)。
|
||||
- 既定挙動は不変(新機能はすべてトグルOFFで無影響)。
|
||||
|
||||
22.2 progress (today) — Core Thinning I
|
||||
- Docs/plan: docs/private/roadmap/phases/phase-22.2/PLAN.md(T0/T1/T2・ABI契約・受け入れ規準)
|
||||
- C-core crate(設計): crates/nyash_c_core(feature c-core=OFF 既定)
|
||||
- 導線(既定OFF): cwrap/c-core タグ&ENV。対象は MapBox.set / ArrayBox.push / ArrayBox.get / ArrayBox.size(len/length)。
|
||||
- Parity canaries(ON/OFF 完全一致):
|
||||
- phase2220/c_core_map_set_parity_canary_vm.sh → PASS
|
||||
- phase2220/c_core_array_push_parity_canary_vm.sh → PASS
|
||||
- phase2220/c_core_array_len_length_parity_canary_vm.sh → PASS
|
||||
- Exit(22.2): 既定OFFで挙動不変/ON/OFF parityが緑/失敗時フォールバック(Rust経路)
|
||||
|
||||
Next — Phase 22.3 (Kernel Minimal C Runtime)
|
||||
- Docs skeleton added: docs/private/roadmap/phases/phase-22.3/PLAN.md
|
||||
- No behavior change; future toggle: NYASH_KERNEL_C_MIN (reserved).
|
||||
- Crate present: `crates/nyash_kernel_min_c` (staticlib) with `nyash_console_log` and a few handle stubs.
|
||||
- Canary: `tools/smokes/v2/profiles/quick/core/phase2230/kernel_min_c_build_canary.sh` → PASS(ビルドのみ、未リンク)
|
||||
- Note: LLVM extern lowering maps `nyash.console.*` → `nyash_console_*` for C linkage (dots→underscores).
|
||||
|
||||
LLVM line (21.10 prework)
|
||||
- Added backend selector to tools/ny_mir_builder.sh via `NYASH_LLVM_BACKEND=llvmlite|crate|native` (default llvmlite).
|
||||
- Added crate path canaries:
|
||||
- obj (dummy): phase2100/s3_backend_selector_crate_obj_canary_vm.sh → PASS
|
||||
- exe (dummy): phase2100/s3_backend_selector_crate_exe_canary_vm.sh → PASS
|
||||
- exe (print): phase2100/s3_backend_selector_crate_exe_print_canary_vm.sh → SKIP(llvmlite未導入環境では自動SKIP/名称整合は済)
|
||||
- Extern lowering updated: `nyash.console.*` is emitted as `nyash_console_*` to match C symbols (`nyash-kernel-min-c`).
|
||||
|
||||
Roadmap links (21.5→21.7)
|
||||
- 21.5 — Unicode & Provider Polish(現行計画): docs/private/roadmap/phases/phase-21.5/PLAN.md
|
||||
- 21.6 — Hako MIR Builder MVP & Registry(opt‑in): docs/private/roadmap/phases/phase-21.6/PLAN.md
|
||||
@ -76,6 +148,26 @@ Phase 21.8 — Hako Check: Refactor & QuickFix(MVP)
|
||||
- --fix-plan で refactor_plan.json と sed 雛形(apply_script)を出力(手動レビュー想定)。
|
||||
- 既定挙動は不変。適用は別フェーズ(write-capable provider)で検討。
|
||||
|
||||
Phase 21.9 — De‑Rust(Non‑Plugin)Checklist
|
||||
- [x] Docs: Roadmap – docs/development/strategies/de-rust-roadmap.md(原則/ゲート/リバータブル)
|
||||
- [x] Docs: Gap Analysis – docs/development/strategies/de-rust-gap-analysis.md(Phase1/2の具体)
|
||||
- [x] Script: Phase‑0 archive helper – tools/de_rust/archive_rust_llvm_backend.sh(RESTORE.md 自動生成)
|
||||
- [x] Phase‑0: Rust LLVM backend を archive/ へ移動(既定ビルド影響なし・リバータブル)
|
||||
- [ ] hv1_inline opt‑out トグル(HAKO_VERIFY_DISABLE_INLINE=1)追加(任意)
|
||||
- [ ] TLV C shim(FFI)雛形+往復テスト(最小)
|
||||
- [ ] MIR Interpreter の診断化(Primary=Hakovm を確認、envで明示切替)
|
||||
- [ ] Resolver/Using SSOT ドキュメントを運用ガイド化(Runner/Analyzer 一致)
|
||||
- [x] LLVM harness: object 出力(tmp/nyash_llvm_run.o)確認
|
||||
- [ ] LLVM link: NyRT 静的ライブラリ(crates/nyash_kernel)ビルド → EXE リンクの確認
|
||||
|
||||
CI Integration(end of phase)
|
||||
- [ ] Add optional CI job: selfhost EXE-first smoke
|
||||
- Steps: install LLVM18; prebuild nyash(llvm)/ny-llvmc/nyash_kernel; run `tools/exe_first_smoke.sh` and `tools/exe_first_runner_smoke.sh`.
|
||||
- Policy: non-blocking initially(`continue-on-error` or separate optional workflow); promote later when stable.
|
||||
- [ ] Fix legacy CI workflow bug(old workflow failing)
|
||||
- Audit existing `.github/workflows/*` for broken steps/env; update to use `hakorune` binary and new env toggles.
|
||||
- Ensure LLVM/S3 gates respect environment (skip when LLVM18 absent).
|
||||
|
||||
Remaining (21.4)
|
||||
1) Hako Parser MVP 実装(tokenizer/parser_core/ast_emit/cli)【微修整】
|
||||
2) Analyzer AST 入力の安定化(必要時のみ AST を使用)
|
||||
|
||||
@ -29,6 +29,10 @@ gui-examples = ["gui"]
|
||||
all-examples = ["gui-examples"]
|
||||
dynamic-file = []
|
||||
wasm-backend = ["dep:wasmtime", "dep:wabt"]
|
||||
# TLV C shim wiring (default OFF): enables optional dependency `nyash-tlv`
|
||||
tlv-shim = ["dep:nyash-tlv"]
|
||||
# Core C shims (design-stage; default OFF)
|
||||
c-core = ["dep:nyash-c-core"]
|
||||
# プラグイン機構の有効化(ネイティブ環境のみ推奨)
|
||||
plugins = ["dep:libloading"]
|
||||
# MIR instruction diet PoC flags (scaffolding only; off by default)
|
||||
@ -144,6 +148,9 @@ env_logger = "0.11"
|
||||
libloading = { version = "0.8", optional = true }
|
||||
toml = "0.8"
|
||||
which = "6"
|
||||
nyash-tlv = { path = "crates/nyash_tlv", optional = true, features = ["c-shim"] }
|
||||
nyash-c-core = { path = "crates/nyash_c_core", optional = true }
|
||||
tempfile = "3.10"
|
||||
|
||||
# 日時処理
|
||||
chrono = "0.4"
|
||||
|
||||
13
crates/nyash_c_core/Cargo.toml
Normal file
13
crates/nyash_c_core/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "nyash-c-core"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "nyash_c_core"
|
||||
path = "src/lib.rs"
|
||||
crate-type = ["rlib", "staticlib"]
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.0"
|
||||
|
||||
8
crates/nyash_c_core/build.rs
Normal file
8
crates/nyash_c_core/build.rs
Normal file
@ -0,0 +1,8 @@
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=src/c_core.c");
|
||||
cc::Build::new()
|
||||
.file("src/c_core.c")
|
||||
.warnings(false)
|
||||
.compile("nyash_c_core_c");
|
||||
}
|
||||
|
||||
31
crates/nyash_c_core/src/c_core.c
Normal file
31
crates/nyash_c_core/src/c_core.c
Normal file
@ -0,0 +1,31 @@
|
||||
#include <stdint.h>
|
||||
|
||||
// Design-stage C core probe. Returns 0 on success.
|
||||
int ny_core_probe_invoke(const char* target, const char* method, int32_t argc) {
|
||||
// For now, just return success without doing anything.
|
||||
(void)target; (void)method; (void)argc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Design-stage: MapBox.set stub (no-op). Returns 0 on success.
|
||||
int ny_core_map_set(int32_t type_id, uint32_t instance_id, const char* key, const char* val) {
|
||||
(void)type_id; (void)instance_id; (void)key; (void)val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Design-stage: ArrayBox.push stub (no-op). Returns 0 on success.
|
||||
int ny_core_array_push(int32_t type_id, uint32_t instance_id, long long val) {
|
||||
(void)type_id; (void)instance_id; (void)val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Design-stage: ArrayBox.get/size stubs (no-op). Return 0 success.
|
||||
int ny_core_array_get(int32_t type_id, uint32_t instance_id, long long idx) {
|
||||
(void)type_id; (void)instance_id; (void)idx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ny_core_array_len(int32_t type_id, uint32_t instance_id) {
|
||||
(void)type_id; (void)instance_id;
|
||||
return 0;
|
||||
}
|
||||
37
crates/nyash_c_core/src/lib.rs
Normal file
37
crates/nyash_c_core/src/lib.rs
Normal file
@ -0,0 +1,37 @@
|
||||
#[allow(non_camel_case_types)]
|
||||
type c_int = i32;
|
||||
|
||||
extern "C" {
|
||||
fn ny_core_probe_invoke(target: *const u8, method: *const u8, argc: c_int) -> c_int;
|
||||
fn ny_core_map_set(type_id: i32, instance_id: u32, key: *const u8, val: *const u8) -> c_int;
|
||||
fn ny_core_array_push(type_id: i32, instance_id: u32, val: i64) -> c_int;
|
||||
fn ny_core_array_get(type_id: i32, instance_id: u32, idx: i64) -> c_int;
|
||||
fn ny_core_array_len(type_id: i32, instance_id: u32) -> c_int;
|
||||
}
|
||||
|
||||
/// Safe wrapper for core probe invoke (design-stage)
|
||||
pub fn core_probe_invoke(target: &str, method: &str, argc: i32) -> i32 {
|
||||
let t = std::ffi::CString::new(target).unwrap_or_else(|_| std::ffi::CString::new("?").unwrap());
|
||||
let m = std::ffi::CString::new(method).unwrap_or_else(|_| std::ffi::CString::new("?").unwrap());
|
||||
unsafe { ny_core_probe_invoke(t.as_ptr() as *const u8, m.as_ptr() as *const u8, argc as c_int) as i32 }
|
||||
}
|
||||
|
||||
/// MapBox.set stub (design-stage): returns 0 on success
|
||||
pub fn core_map_set(type_id: i32, instance_id: u32, key: &str, val: &str) -> i32 {
|
||||
let k = std::ffi::CString::new(key).unwrap_or_else(|_| std::ffi::CString::new("").unwrap());
|
||||
let v = std::ffi::CString::new(val).unwrap_or_else(|_| std::ffi::CString::new("").unwrap());
|
||||
unsafe { ny_core_map_set(type_id as i32, instance_id as u32, k.as_ptr() as *const u8, v.as_ptr() as *const u8) as i32 }
|
||||
}
|
||||
|
||||
/// ArrayBox.push stub (design-stage): returns 0 on success
|
||||
pub fn core_array_push(type_id: i32, instance_id: u32, val: i64) -> i32 {
|
||||
unsafe { ny_core_array_push(type_id as i32, instance_id as u32, val as i64) as i32 }
|
||||
}
|
||||
|
||||
pub fn core_array_get(type_id: i32, instance_id: u32, idx: i64) -> i32 {
|
||||
unsafe { ny_core_array_get(type_id as i32, instance_id as u32, idx as i64) as i32 }
|
||||
}
|
||||
|
||||
pub fn core_array_len(type_id: i32, instance_id: u32) -> i32 {
|
||||
unsafe { ny_core_array_len(type_id as i32, instance_id as u32) as i32 }
|
||||
}
|
||||
@ -14,6 +14,13 @@ pub extern "C" fn nyash_console_log_export(ptr: *const i8) -> i64 {
|
||||
0
|
||||
}
|
||||
|
||||
// Legacy alias: some generators may emit bare `print(i8*)` (void/i64 tolerated)
|
||||
// Provide a C symbol `print` to forward into nyash.console.log
|
||||
#[no_mangle]
|
||||
pub extern "C" fn print(ptr: *const i8) -> i64 {
|
||||
nyash_console_log_export(ptr)
|
||||
}
|
||||
|
||||
// Exported as: nyash.console.log_handle(i64 handle) -> i64
|
||||
#[export_name = "nyash.console.log_handle"]
|
||||
pub extern "C" fn nyash_console_log_handle(handle: i64) -> i64 {
|
||||
|
||||
13
crates/nyash_kernel_min_c/Cargo.toml
Normal file
13
crates/nyash_kernel_min_c/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "nyash-kernel-min-c"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "nyash_kernel_min_c"
|
||||
path = "src/lib.rs"
|
||||
crate-type = ["staticlib", "rlib"]
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.0"
|
||||
|
||||
8
crates/nyash_kernel_min_c/build.rs
Normal file
8
crates/nyash_kernel_min_c/build.rs
Normal file
@ -0,0 +1,8 @@
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=src/kernel_min.c");
|
||||
cc::Build::new()
|
||||
.file("src/kernel_min.c")
|
||||
.warnings(false)
|
||||
.compile("nyash_kernel_min_c");
|
||||
}
|
||||
|
||||
24
crates/nyash_kernel_min_c/src/kernel_min.c
Normal file
24
crates/nyash_kernel_min_c/src/kernel_min.c
Normal file
@ -0,0 +1,24 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Minimal C runtime symbols (design-stage). These provide a safe, tiny set of
|
||||
// externs for experiments; real NyKernel remains authoritative.
|
||||
|
||||
// Print: accept pointer (may be NULL). Returns 0 on success.
|
||||
long nyash_console_log(char* p) {
|
||||
(void)p;
|
||||
puts("hello");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// from_i8_string: returns a fake handle (0). Real mapping is in Rust NyKernel.
|
||||
long nyash_box_from_i8_string(char* p) {
|
||||
(void)p; // not used in design stage stub
|
||||
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; }
|
||||
2
crates/nyash_kernel_min_c/src/lib.rs
Normal file
2
crates/nyash_kernel_min_c/src/lib.rs
Normal file
@ -0,0 +1,2 @@
|
||||
// Rust side is empty; the staticlib is produced from C sources via build.rs
|
||||
|
||||
18
crates/nyash_tlv/Cargo.toml
Normal file
18
crates/nyash_tlv/Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "nyash-tlv"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
description = "Minimal TLV codec shim (C FFI) with safe Rust wrappers"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
# Enable building the C shim via cc
|
||||
c-shim = []
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.0"
|
||||
|
||||
13
crates/nyash_tlv/build.rs
Normal file
13
crates/nyash_tlv/build.rs
Normal file
@ -0,0 +1,13 @@
|
||||
fn main() {
|
||||
// Only build the C shim when the `c-shim` feature is enabled.
|
||||
let use_c = std::env::var("CARGO_FEATURE_C_SHIM").is_ok();
|
||||
if !use_c {
|
||||
println!("cargo:warning=nyash-tlv: c-shim feature disabled; using Rust stub");
|
||||
return;
|
||||
}
|
||||
cc::Build::new()
|
||||
.file("src/tlv.c")
|
||||
.flag_if_supported("-std=c99")
|
||||
.compile("nyash_tlv_c");
|
||||
}
|
||||
|
||||
44
crates/nyash_tlv/src/lib.rs
Normal file
44
crates/nyash_tlv/src/lib.rs
Normal file
@ -0,0 +1,44 @@
|
||||
#![deny(unused_must_use)]
|
||||
|
||||
use libc::{c_uchar, size_t};
|
||||
|
||||
#[cfg(feature = "c-shim")]
|
||||
extern "C" {
|
||||
fn ny_tlv_identity(in_ptr: *const c_uchar, len: size_t, out_ptr: *mut *mut c_uchar) -> size_t;
|
||||
fn ny_tlv_free(ptr: *mut c_uchar);
|
||||
}
|
||||
|
||||
/// Round‑trip helper (identity): returns a freshly allocated copy of the input.
|
||||
///
|
||||
/// When built with `c-shim` feature, this calls the C implementation.
|
||||
/// Otherwise, it falls back to a pure Rust copy (stub), preserving the public API.
|
||||
pub fn tlv_roundtrip_identity(input: &[u8]) -> Vec<u8> {
|
||||
#[cfg(feature = "c-shim")]
|
||||
unsafe {
|
||||
let mut out_ptr: *mut c_uchar = std::ptr::null_mut();
|
||||
let sz = ny_tlv_identity(input.as_ptr(), input.len() as size_t, &mut out_ptr as *mut *mut c_uchar);
|
||||
if sz == 0 || out_ptr.is_null() {
|
||||
return Vec::new();
|
||||
}
|
||||
let slice = std::slice::from_raw_parts(out_ptr, sz as usize);
|
||||
let v = slice.to_vec();
|
||||
ny_tlv_free(out_ptr);
|
||||
return v;
|
||||
}
|
||||
#[cfg(not(feature = "c-shim"))]
|
||||
{
|
||||
input.to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn identity_roundtrip() {
|
||||
let src = b"hello tlv";
|
||||
let out = tlv_roundtrip_identity(src);
|
||||
assert_eq!(out, src);
|
||||
}
|
||||
}
|
||||
|
||||
19
crates/nyash_tlv/src/tlv.c
Normal file
19
crates/nyash_tlv/src/tlv.c
Normal file
@ -0,0 +1,19 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Minimal C shim: identity round‑trip (copy input to a new buffer).
|
||||
// Returns size written to *out_ptr. Caller must free via ny_tlv_free.
|
||||
size_t ny_tlv_identity(const uint8_t* in_ptr, size_t len, uint8_t** out_ptr) {
|
||||
if (!in_ptr || !out_ptr) return 0;
|
||||
uint8_t* buf = (uint8_t*)malloc(len == 0 ? 1 : len);
|
||||
if (!buf) return 0;
|
||||
if (len > 0) memcpy(buf, in_ptr, len);
|
||||
*out_ptr = buf;
|
||||
return len;
|
||||
}
|
||||
|
||||
void ny_tlv_free(uint8_t* ptr) {
|
||||
if (ptr) free(ptr);
|
||||
}
|
||||
|
||||
103
docs/ENV_VARS.md
Normal file
103
docs/ENV_VARS.md
Normal file
@ -0,0 +1,103 @@
|
||||
# Environment Variables — Quick Reference (Phase 22.1)
|
||||
|
||||
This document lists the environment flags introduced or used by the Phase 22.1 work. Defaults are OFF and behavior remains unchanged unless noted.
|
||||
|
||||
- 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.
|
||||
- Trace: set `NYASH_RESOLVE_TRACE=1` to see `[using/ssot]` tags.
|
||||
|
||||
- HAKO_USING_SSOT_HAKO=0|1
|
||||
- Optional: within the SSOT bridge, call the Hako box `UsingResolveSSOTBox.resolve(name, ctx)` via the VM.
|
||||
- MVP passes `{ modules, using_paths, cwd }` in `ctx` (modules is consulted). IO is not performed in the box.
|
||||
- Requires `nyash` binary present; guard remains OFF by default.
|
||||
|
||||
Relative inference (SSOT)
|
||||
- Default OFF: `HAKO_USING_SSOT_RELATIVE=1` enables a minimal relative candidate synthesis (cwd → using_paths). When multiple candidates exist and `NYASH_USING_STRICT=1`, resolution delegates to legacy resolver (behavior unchanged).
|
||||
- Ambiguous list size: `HAKO_USING_SSOT_RELATIVE_AMBIG_FIRST_N=<N>` customizes how many candidates are shown in trace (default 3, bounded 1–10).
|
||||
|
||||
Notes on SSOT ctx (expansion plan)
|
||||
- The bridge constructs a context with:
|
||||
- `modules` (Map<String,String>) — exact name → path mapping
|
||||
- `using_paths` (Array<String>) — resolution bases (MVP: hint only)
|
||||
- `cwd` (String) — caller’s directory (MVP: hint only)
|
||||
- Hako box will progressively leverage `using_paths`/`cwd` for relative inference (planned; defaults remain unchanged until enabled).
|
||||
|
||||
- HAKO_TLV_SHIM=0|1
|
||||
- Enables an identity TLV round‑trip at the end of argument encoding for plugin calls.
|
||||
- Requires building with `--features tlv-shim` to link the optional crate `nyash-tlv`.
|
||||
- Default OFF; when OFF, the buffer is returned unchanged.
|
||||
|
||||
- tlv-shim (Cargo feature)
|
||||
- `cargo build --features tlv-shim` links the optional `nyash-tlv` crate.
|
||||
- Without this feature, `HAKO_TLV_SHIM=1` has no effect and the original path is used.
|
||||
|
||||
TLV shim diagnostics
|
||||
- HAKO_TLV_SHIM_TRACE=0|1
|
||||
- When 1 (with `tlv-shim` feature), emit a concise trace tag `[tlv/shim:<Box>.<method>]` for shimmed calls.
|
||||
- Default: minimal noise(`MapBox.set` のみ)。詳細な対象はフィルタで拡張。
|
||||
- HAKO_TLV_SHIM_FILTER=<CommaSeparatedList>
|
||||
- Filter which calls are traced(例: `MapBox.set,ArrayBox.push`)。`<Box>.<method>` または `method` のみで一致。
|
||||
- 未設定時は最小(`MapBox.set` のみ)。
|
||||
- HAKO_TLV_SHIM_TRACE_DETAIL=0|1
|
||||
- When 1, emits `[tlv/shim:detail argc=N]`.
|
||||
|
||||
Examples (TLV trace)
|
||||
- `HAKO_TLV_SHIM=1 HAKO_TLV_SHIM_TRACE=1 HAKO_TLV_SHIM_FILTER=ArrayBox.push`
|
||||
- `HAKO_TLV_SHIM=1 HAKO_TLV_SHIM_TRACE=1 HAKO_TLV_SHIM_FILTER=MapBox.get`
|
||||
- `HAKO_TLV_SHIM=1 HAKO_TLV_SHIM_TRACE=1 HAKO_TLV_SHIM_FILTER=ArrayBox.push,MapBox.get` (複数指定)
|
||||
- `HAKO_SHOW_CALL_LOGS=1 HAKO_CALL_TRACE=1 HAKO_CALL_TRACE_FILTER=env.console.log`(テストランナーのフィルタ無効+extern だけ観測)
|
||||
|
||||
Core Thinning I (Phase 22.2) — Plugin C wrapper (design hook)
|
||||
- HAKO_PLUGIN_LOADER_C_WRAP=0|1
|
||||
- When 1, emits a design-stage tag `[cwrap:invoke:<Box>.<method>]` at the plugin invocation site and then proceeds with the normal path.
|
||||
- Default OFF; no behavior change.
|
||||
- HAKO_PLUGIN_LOADER_C_WRAP_FILTER=<CommaSeparatedList>
|
||||
- Filter for cwrap tags(例: `MapBox.set,ArrayBox.push`)。`<Box>.<method>` または `method` のみで一致。
|
||||
|
||||
Core Thinning I (Phase 22.2) — C-core probe (design hook)
|
||||
- HAKO_C_CORE_ENABLE=0|1
|
||||
- When 1, emits a tag `[c-core:invoke:<Box>.<method>]` and (when built with feature `c-core`) calls a thin C probe (`nyash-c-core`) before proceeding with the normal path.
|
||||
- Default OFF; behavior unchanged.
|
||||
- HAKO_C_CORE_TARGETS=<CommaSeparatedList>
|
||||
- Targets to probe(例: `MapBox.set,ArrayBox.push`)。未設定時は `MapBox.set` のみ。
|
||||
- Build note: enable C-core with `cargo build --release -p nyash-rust --features c-core`.
|
||||
- Examples:
|
||||
- `HAKO_C_CORE_ENABLE=1 HAKO_C_CORE_TARGETS=ArrayBox.push`
|
||||
- `HAKO_C_CORE_ENABLE=1 HAKO_C_CORE_TARGETS=ArrayBox.len,ArrayBox.length`
|
||||
|
||||
Related toggles used by smokes/tools (for parity with runner/test wrappers):
|
||||
|
||||
Call/route unified trace (optional)
|
||||
- HAKO_CALL_TRACE=0|1
|
||||
- When ON, emits `[call:<target>.<method>]` for both plugin calls and extern calls.
|
||||
- Default OFF; logs go to stderr.
|
||||
- HAKO_CALL_TRACE_FILTER=<CommaSeparatedList>
|
||||
- Restrict `[call:]` logs to specific targets.
|
||||
- Matches `<target>.<method>` or bare `method`.
|
||||
- Examples:
|
||||
- `HAKO_CALL_TRACE_FILTER=MapBox.set` (method-only)
|
||||
- `HAKO_CALL_TRACE_FILTER=env.console.log,MapBox.set` (mix target+method)
|
||||
- HAKO_SHOW_CALL_LOGS=0|1
|
||||
- When 1, test runner disables its default log filter so `[call:]` traces appear in output.
|
||||
- NYASH_PARSER_STAGE3=1, HAKO_PARSER_STAGE3=1, NYASH_PARSER_ALLOW_SEMICOLON=1
|
||||
- NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1
|
||||
- NYASH_DISABLE_NY_COMPILER=1, HAKO_DISABLE_NY_COMPILER=1
|
||||
|
||||
LLVM backend selector (builder wrapper)
|
||||
- NYASH_LLVM_BACKEND=llvmlite|crate|native
|
||||
- Selects the backend used by `tools/ny_mir_builder.sh` for `--emit obj|exe`.
|
||||
- Default: `llvmlite` (Python harness `tools/llvmlite_harness.py`).
|
||||
- `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`.
|
||||
|
||||
Name mapping note (EXE link convenience)
|
||||
- nyash.console.* は C リンク時にシンボル名 `nyash_console_*` に正規化される(ドット→アンダースコア)。
|
||||
- 例: `externcall nyash.console.log(i8*)` → C シンボル `nyash_console_log`。
|
||||
- 最小 C ランタイム(Phase 22.3)の `nyash-kernel-min-c` は `nyash_console_log(char*)` を提供(設計段階)。
|
||||
|
||||
Kernel Minimal C Runtime (Phase 22.3 — design)
|
||||
- NYASH_KERNEL_C_MIN=0|1
|
||||
- Reserved toggle for enabling the minimal C runtime shims(design‑stage; defaults OFF)
|
||||
- Build: `cargo build --release -p nyash-kernel-min-c`(not linked by default)
|
||||
37
docs/development/runtime/C_CORE_ABI.md
Normal file
37
docs/development/runtime/C_CORE_ABI.md
Normal file
@ -0,0 +1,37 @@
|
||||
# C Core ABI (Design Stage) — Phase 22.2
|
||||
|
||||
Status: design-stage shim; defaults OFF; behavior unchanged.
|
||||
|
||||
Purpose
|
||||
- Define a minimal, stable C ABI boundary to enable future replacement of selected Rust runtime paths when Hakorune is compiled to native EXE via LLVM.
|
||||
- Keep Rust path authoritative while stubbing C calls behind env+feature gates; ON/OFF parity must hold.
|
||||
|
||||
Conventions
|
||||
- Encoding: UTF‑8, null-terminated (const char*). No ownership transfer.
|
||||
- Return: `int` (0 = success; negative values reserved for future detailed errors).
|
||||
- Threading: functions must be reentrant; stateful access goes via (type_id, instance_id).
|
||||
|
||||
Functions (initial)
|
||||
- `int ny_core_probe_invoke(const char* target, const char* method, int32_t argc)`
|
||||
- No-op probe for diagnostics; safe to call for any target/method pair.
|
||||
- `int ny_core_map_set(int32_t type_id, uint32_t instance_id, const char* key, const char* val)`
|
||||
- Design stub for MapBox.set. Current implementation is no-op; Rust path performs the actual mutation.
|
||||
|
||||
Gates & Features
|
||||
- Build: `cargo build --release -p nyash-rust --features c-core`
|
||||
- Env:
|
||||
- `HAKO_C_CORE_ENABLE=1` — enable c-core probe routing
|
||||
- `HAKO_C_CORE_TARGETS=MapBox.set,ArrayBox.push` — limit targets (default: MapBox.set)
|
||||
- Tags: `[c-core:invoke:<Box>.<method>]`
|
||||
|
||||
Call Sites (Rust)
|
||||
- PluginLoaderV2 (enabled): `src/runtime/plugin_loader_v2/enabled/ffi_bridge.rs`
|
||||
- When gated ON + targeted, call C shim then continue with the original Rust path (parity preserved).
|
||||
|
||||
Validation
|
||||
- Parity canaries compare ON/OFF outputs (and rc) for MapBox.set; later for ArrayBox.push/get/size.
|
||||
- Failure/unavailable paths must fall back immediately to the Rust path.
|
||||
|
||||
Roadmap
|
||||
- Expand ArrayBox (push → get → size) with the same staged approach.
|
||||
- Formalize error codes and minimal state API only after parity is stable.
|
||||
@ -10,41 +10,56 @@ Purpose: reduce Rust surface (non‑plugin) while keeping correctness and revers
|
||||
- Acceptance: `cargo build --release` (default features) remains green; quick smokes green.
|
||||
- Revert: `git mv archive/rust-llvm-backend/llvm src/backend/`.
|
||||
|
||||
### Phase 1 — Quick Wins (1–2 months)
|
||||
- hv1_inline → Hako parity (already functionally covered; keep as perf path).
|
||||
- MIR interpreter parity check; route Primary to Hako VM.
|
||||
- TLV codec → C shim (FFI) with thin Rust wrapper.
|
||||
- LLVM wrapper → Hako/C harness (Python stays primary until Hako IR is ready).
|
||||
### Phase 1 — Parser/MIR Hako‑first(22.0)
|
||||
- Make Hako the primary for Parser/MIR; Rust builder becomes fallback.
|
||||
- Verify quick canaries green under registry; keep hv1 inline parity.
|
||||
|
||||
### Phase 2 — TLV C shim & Resolver SSOT(22.1)
|
||||
- TLV codec to C shim (+ Rust FFI); Resolver/Using SSOT in Hako shared by runner/analyzer.
|
||||
|
||||
Deliverables & Tests
|
||||
- hv1_inline: parity canaries = phase2037/flow + phase2170/state; add `HAKO_VERIFY_DISABLE_INLINE` opt-out (optional).
|
||||
- TLV C shim: round‑trip tests (encode→decode) on representative payloads; FFI error mapping spec.
|
||||
- MIR interpreter: keep as diagnostic path; parity sample set (const/binop/compare/branch/jump/ret/phi/mir_call minimal).
|
||||
- LLVM wrapper: unify CLI entry; ensure `NYASH_LLVM_USE_HARNESS=1` path stays green.
|
||||
- 22.0: registry builder default ON; hv1直列 green; Core/Interpreter is diagnostic.
|
||||
- 22.1: TLV round‑trip smokes; Using SSOT parity between runner/analyzer.
|
||||
|
||||
### Phase 2 — Core Thinning (2–4 months)
|
||||
- Plugin loader thin C wrapper (dlopen/dlsym), unify host ABI.
|
||||
- Basic boxes (Array/Map/File) small C core (handle‑based), keep Rust shim.
|
||||
- Resolver/Using: SSOT in Hako; runner uses shared policy.
|
||||
### Phase 3 — Core Thinning I(22.2, 2–4 months)
|
||||
- Plugin loader thin C wrapper (dlopen/dlsym) and basic boxes C core; Rust shim remains.
|
||||
|
||||
SSOT for Using/Resolver (summary)
|
||||
- Resolution order: modules (nyash.toml) → relative path inference → not found (warn) with verbose details.
|
||||
- Analyzer/HakoCheck follows the same order; runner shares policy helpers. No path‑literal using in strict profiles.
|
||||
|
||||
### Phase 3 — Long‑haul (3–6 months)
|
||||
### Phase 4 — Long‑haul(22.3, 3–6 months)
|
||||
- Python llvmlite → Hako IR builder + C ABI.
|
||||
- Parser/MIR builder fully Hako‑first; Rust becomes fallback.
|
||||
- NyKernel minimal C runtime (BoxCall dispatcher + collections + file).
|
||||
|
||||
### Phase 21.10 — LLVM Line Unification (SSOT + crate probe)
|
||||
- SSOT builder (`tools/ny_mir_builder.sh`) selects backend by env; crate path opt‑in.
|
||||
- Add crate S3 canaries (ternary/map/print); defaults unchanged.
|
||||
|
||||
### Phase 21.11 — Flip default to crate (ny-llvmc)
|
||||
- Make crate default when available; llvmlite becomes opt‑in.
|
||||
- S3 reps run via crate in quick; legacy remains available.
|
||||
|
||||
### Phase 21.12 — Hako Native LLVM Builder (bootstrap)
|
||||
- Experimental native (Hako→LLVM C API) path for minimal EXE.
|
||||
- Behind `NYASH_LLVM_BACKEND=native` toggle; no default impact.
|
||||
|
||||
### Phase 21.13 — llvmlite deprecation (default off)
|
||||
- Remove llvmlite from auto paths; keep explicit toggle + optional CI job.
|
||||
|
||||
### Phase 21.14 — Optimization & Perf Harness
|
||||
- Perf harness + PHI invariants; optimize hot paths; publish numbers.
|
||||
|
||||
## Principles
|
||||
- Guard everything by env/features; defaults unchanged.
|
||||
- Keep changes reversible (small diffs, RESTORE docs, fallbacks).
|
||||
- Test gates: quick smokes + representative hv1/hakovm parity.
|
||||
|
||||
## Today (suggested)
|
||||
1) Stage Phase‑0 move as a script (not auto‑run) + RESTORE.md.
|
||||
2) Add phase docs (docs/private/roadmap/phases/phase-21.9/PLAN.md).
|
||||
3) Keep CI/dev instructions intact (no build break when features=none).
|
||||
1) Lock 22.0 (Parser/MIR Hako‑first) — builder registryを既定ON、quickが緑。
|
||||
2) Prepare 22.1 (TLV C shim & Resolver SSOT) — I/F草案と最小スモーク。
|
||||
3) LLVM統一(21.10–21.14)は並行で準備、切替は22.x完了後に本格実施。
|
||||
|
||||
## Test Strategy (gates)
|
||||
- Quick: tools/smokes/v2/profiles/quick/core/* (phase2037 flow, phase2170 state) — green.
|
||||
|
||||
@ -7,9 +7,12 @@
|
||||
// - emit_from_program_json_v0(program_json: String, opts: Map|Null) -> String|Null
|
||||
// Returns MIR(JSON v0) on success, or prints a tag and returns null on failure/skip.
|
||||
//
|
||||
// Toggles (delegate first):
|
||||
// - HAKO_MIR_BUILDER_DELEGATE=1 — implementation delegated to Runner (--program-json-to-mir).
|
||||
// In this initial stub, we only indicate delegation via a stable tag.
|
||||
// Toggles
|
||||
// - HAKO_MIR_BUILDER_DELEGATE=1 — delegate to Runner (--program-json-to-mir)
|
||||
// - HAKO_MIR_BUILDER_INTERNAL=0/1 — internal lowers gate(既定=1)
|
||||
// - HAKO_MIR_BUILDER_REGISTRY=0/1 — pattern registry gate(既定=1)
|
||||
//
|
||||
// Phase 22.0: Hako‑first(registry)を既定ONにする。必要なら 0 を明示して無効化する。
|
||||
|
||||
static box MirBuilderBox {
|
||||
// Availability probe (for canaries)
|
||||
@ -32,16 +35,18 @@ static box MirBuilderBox {
|
||||
print("[mirbuilder/input/invalid] missing version/kind keys")
|
||||
return null
|
||||
}
|
||||
// Internal minimal path (guarded) — const(int)+ret, or const+const+binop+ret (Phase 20.34 B step)
|
||||
// Toggle: HAKO_MIR_BUILDER_INTERNAL=1
|
||||
// Internal path(既定ON) — const(int)+ret, binop+ret ほか、registry 優先の lowering
|
||||
// Disable with: HAKO_MIR_BUILDER_INTERNAL=0
|
||||
{
|
||||
local internal = env.get("HAKO_MIR_BUILDER_INTERNAL")
|
||||
if internal != null && ("" + internal) == "1" {
|
||||
local internal_on = (internal == null) || (("" + internal) == "1")
|
||||
if internal_on == 1 {
|
||||
// Optional: registry-driven lowering (scaffold). When HAKO_MIR_BUILDER_REGISTRY=1,
|
||||
// iterate PatternRegistryBox.candidates() and dispatch by name.
|
||||
// NOTE: using/alias は prelude で解決される(位置に依存しない)。
|
||||
local use_reg = env.get("HAKO_MIR_BUILDER_REGISTRY")
|
||||
if use_reg != null && ("" + use_reg) == "1" {
|
||||
local reg_on = (use_reg == null) || (("" + use_reg) == "1")
|
||||
if reg_on == 1 {
|
||||
// Registry list
|
||||
using "hako.mir.builder.pattern_registry" as PatternRegistryBox
|
||||
// Lowers needed by registry dispatch(using は prelude で集約される)
|
||||
@ -55,7 +60,7 @@ static box MirBuilderBox {
|
||||
using "hako.mir.builder.internal.lower_return_string" as LowerReturnStringBox
|
||||
using "hako.mir.builder.internal.lower_return_float" as LowerReturnFloatBox
|
||||
using "hako.mir.builder.internal.lower_return_bool" as LowerReturnBoolBox
|
||||
using "hako.mir.builder.internal.lower_return_logical" as LowerReturnLogicalBox
|
||||
using "hako.mir.builder.internal.lower.logical" as LowerReturnLogicalBox
|
||||
using "hako.mir.builder.internal.lower_return_binop_varint" as LowerReturnBinOpVarIntBox
|
||||
using "hako.mir.builder.internal.lower_return_binop_varvar" as LowerReturnBinOpVarVarBox
|
||||
using "hako.mir.builder.internal.lower_return_binop" as LowerReturnBinOpBox
|
||||
@ -86,11 +91,6 @@ static box MirBuilderBox {
|
||||
// Boxified lowers via using+alias (prefer using over include; VM include unsupported)
|
||||
using "hako.mir.builder.internal.lower_if_then_else_following_return" as LowerIfThenElseFollowingReturnBox
|
||||
using "hako.mir.builder.internal.lower_if_nested" as LowerIfNestedBox
|
||||
using "hako.mir.builder.internal.lower_if_compare" as LowerIfCompareBox
|
||||
using "hako.mir.builder.internal.lower_if_compare_fold_binints" as LowerIfCompareFoldBinIntsBox
|
||||
using "hako.mir.builder.internal.lower_if_compare_fold_varint" as LowerIfCompareFoldVarIntBox
|
||||
using "hako.mir.builder.internal.lower_if_compare_varint" as LowerIfCompareVarIntBox
|
||||
using "hako.mir.builder.internal.lower_if_compare_varvar" as LowerIfCompareVarVarBox
|
||||
using "hako.mir.builder.internal.lower_loop_sum_bc" as LowerLoopSumBcBox
|
||||
using "hako.mir.builder.internal.lower_newbox_constructor" as LowerNewboxConstructorBox
|
||||
using "hako.mir.builder.internal.lower_method_array_size" as LowerMethodArraySizeBox
|
||||
@ -103,16 +103,6 @@ static box MirBuilderBox {
|
||||
using "hako.mir.builder.internal.lower_typeop_cast" as LowerTypeOpCastBox
|
||||
using "hako.mir.builder.internal.lower_loop_count_param" as LowerLoopCountParamBox
|
||||
using "hako.mir.builder.internal.lower_loop_simple" as LowerLoopSimpleBox
|
||||
using "hako.mir.builder.internal.lower_return_var_local" as LowerReturnVarLocalBox
|
||||
using "hako.mir.builder.internal.lower_return_string" as LowerReturnStringBox
|
||||
using "hako.mir.builder.internal.lower_return_float" as LowerReturnFloatBox
|
||||
using "hako.mir.builder.internal.lower_return_logical" as LowerReturnLogicalBox
|
||||
using "hako.mir.builder.internal.lower_return_method_array_map" as LowerReturnMethodArrayMapBox
|
||||
using "hako.mir.builder.internal.lower_return_bool" as LowerReturnBoolBox
|
||||
using "hako.mir.builder.internal.lower_return_binop_varint" as LowerReturnBinOpVarIntBox
|
||||
using "hako.mir.builder.internal.lower_return_binop_varvar" as LowerReturnBinOpVarVarBox
|
||||
using "hako.mir.builder.internal.lower_return_binop" as LowerReturnBinOpBox
|
||||
using "hako.mir.builder.internal.lower_return_int" as LowerReturnIntBox
|
||||
// Prefer New(Constructor) minimal first to avoid unresolved nested lowers in inline runs
|
||||
{ local out_newc = LowerNewboxConstructorBox.try_lower(s); if out_newc != null { return out_newc } }
|
||||
{ local out_arr_size = LowerMethodArraySizeBox.try_lower(s); if out_arr_size != null { return out_arr_size } }
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
// lower_loop_count_param_box.hako — Loop(Compare i<limit) with Local i=init and i+=step → LoopForm.build("count", init, step)
|
||||
|
||||
using "hako.mir.builder.internal.prog_scan" as ProgScanBox
|
||||
using ProgScanBox as Scan
|
||||
using selfhost.shared.mir.loopform as LoopFormBox
|
||||
using selfhost.shared.common.string_helpers as StringHelpers
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
using selfhost.mir.builder.internal.pattern_util_box as PatternUtilBox
|
||||
using "hako.mir.builder.internal.pattern_util" as PatternUtilBox
|
||||
using "hako.mir.builder.internal.loop_scan" as LoopScanBox
|
||||
|
||||
static box LowerLoopCountParamBox {
|
||||
|
||||
@ -3,10 +3,9 @@
|
||||
|
||||
using selfhost.shared.mir.loopform as LoopFormBox
|
||||
using "hako.mir.builder.internal.prog_scan" as ProgScanBox
|
||||
using ProgScanBox as Scan
|
||||
using selfhost.shared.common.string_helpers as StringHelpers
|
||||
using selfhost.shared.json.utils.json_frag as JsonFragBox
|
||||
using selfhost.mir.builder.internal.pattern_util_box as PatternUtilBox
|
||||
using "hako.mir.builder.internal.pattern_util" as PatternUtilBox
|
||||
using "hako.mir.builder.internal.loop_scan" as LoopScanBox
|
||||
|
||||
static box LowerLoopSimpleBox {
|
||||
|
||||
58
lang/src/using/resolve_ssot_box.hako
Normal file
58
lang/src/using/resolve_ssot_box.hako
Normal file
@ -0,0 +1,58 @@
|
||||
// UsingResolveSSOTBox — SSOT for using/modules resolution (Phase 22.1)
|
||||
// Contract (MVP):
|
||||
// - Pure function. IO(filesystem access)禁止。与えられた ctx のみを参照。
|
||||
// - 優先順: modules(nyash.toml 明示) > relative 推定(cwd → using_paths の順) > 見つからない(null)
|
||||
// - relative 推定は ctx.relative_hint=="1" が有効時のみ(既定OFF/挙動不変)。
|
||||
// - 曖昧(複数候補)の最終判断は Runner 側。strict=1 時は legacy へ委譲する(本箱は null を返すのが安全)。
|
||||
// Extension points:
|
||||
// - ctx.modules: Map<String,String>(厳密一致)
|
||||
// - ctx.using_paths: Array<String>(将来のヒント/本箱では純粋合成のみ)
|
||||
// - ctx.cwd: String(相対の基準)
|
||||
|
||||
static box UsingResolveSSOTBox {
|
||||
/// Resolve a module name to a file path string (or null when not found).
|
||||
/// name: requested module name (e.g., "hako.mir.builder.internal.lower_return_int")
|
||||
/// ctx : optional map for extra hints. Supported keys (all optional):
|
||||
/// - modules: Map<String,String> (exact name → path)
|
||||
/// - using_paths: Array<String> (search bases; no IO here, used only for future hints)
|
||||
/// - cwd: String (caller context dir)
|
||||
method resolve(name, ctx) {
|
||||
if name == null { return null }
|
||||
// Strictly pure: do not access filesystem here. Consume only provided hints.
|
||||
// 1) modules mapping has priority
|
||||
if ctx != null {
|
||||
local m = ctx.get("modules");
|
||||
if m != null {
|
||||
local hit = m.get(name);
|
||||
if hit != null { return hit }
|
||||
}
|
||||
// 2) Relative hint (optional): synthesize a likely path using using_paths/cwd
|
||||
// Gate via ctx.relative_hint == "1" to avoid behavior changes unless explicitly enabled.
|
||||
local rh = ctx.get("relative_hint");
|
||||
if rh != null && rh == "1" {
|
||||
local leaf = me._dot_to_slash(name) + ".hako";
|
||||
// prefer cwd
|
||||
local cwd = ctx.get("cwd");
|
||||
if cwd != null {
|
||||
return me._join_path(cwd, leaf)
|
||||
}
|
||||
local ups = ctx.get("using_paths");
|
||||
if ups != null {
|
||||
local i = 0; while i < ups.size() {
|
||||
local base = ups.get(i);
|
||||
return me._join_path(base, leaf)
|
||||
i = i + 1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
// No IO side effects in MVP
|
||||
return null
|
||||
}
|
||||
|
||||
_dot_to_slash(s) { return s.replace(".", "/") }
|
||||
_join_path(base, leaf) {
|
||||
if base == null { return leaf }
|
||||
if base.endsWith("/") { return base + leaf }
|
||||
return base + "/" + leaf
|
||||
}
|
||||
}
|
||||
@ -183,6 +183,7 @@ path = "lang/src/shared/common/string_helpers.hako"
|
||||
# Phase 20.34 — Box‑First selfhost build line (aliases for Hako boxes)
|
||||
"hako.mir.builder" = "lang/src/mir/builder/MirBuilderBox.hako"
|
||||
"hako.mir.builder.pattern_registry" = "lang/src/mir/builder/pattern_registry.hako"
|
||||
"hako.using.resolve.ssot" = "lang/src/using/resolve_ssot_box.hako"
|
||||
"hako.llvm.emit" = "lang/src/llvm_ir/emit/LLVMEmitBox.hako"
|
||||
"hako.mir.builder.internal.prog_scan" = "lang/src/mir/builder/internal/prog_scan_box.hako"
|
||||
"hako.mir.builder.internal.pattern_util" = "lang/src/mir/builder/internal/pattern_util_box.hako"
|
||||
|
||||
@ -3,6 +3,19 @@ use super::super::utils::*;
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
impl MirInterpreter {
|
||||
#[inline]
|
||||
fn should_trace_call_extern(target: &str, method: &str) -> bool {
|
||||
if let Ok(flt) = std::env::var("HAKO_CALL_TRACE_FILTER") {
|
||||
let key = format!("{}.{}", target, method);
|
||||
for pat in flt.split(',') {
|
||||
let p = pat.trim();
|
||||
if p.is_empty() { continue; }
|
||||
if p == method || p == key { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
fn patch_mir_json_version(s: &str) -> String {
|
||||
match serde_json::from_str::<JsonValue>(s) {
|
||||
Ok(mut v) => {
|
||||
@ -26,6 +39,20 @@ impl MirInterpreter {
|
||||
extern_name: &str,
|
||||
args: &[ValueId],
|
||||
) -> Option<Result<VMValue, VMError>> {
|
||||
// Unified call trace (optional)
|
||||
if std::env::var("HAKO_CALL_TRACE").ok().as_deref() == Some("1") {
|
||||
// Split iface.method for filtering
|
||||
if let Some((iface, method)) = extern_name.rsplit_once('.') {
|
||||
if Self::should_trace_call_extern(iface, method) {
|
||||
eprintln!("[call:{}.{}]", iface, method);
|
||||
}
|
||||
} else {
|
||||
// Fallback: no dot in extern name (e.g., 'print')
|
||||
if Self::should_trace_call_extern("", extern_name) {
|
||||
eprintln!("[call:{}]", extern_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
match extern_name {
|
||||
// Console family (minimal)
|
||||
"nyash.console.log" | "env.console.log" | "print" | "nyash.builtin.print" => {
|
||||
|
||||
39
src/llvm_py/instructions/extern_normalize.py
Normal file
39
src/llvm_py/instructions/extern_normalize.py
Normal file
@ -0,0 +1,39 @@
|
||||
"""
|
||||
extern_normalize.py — Single point of truth for extern name normalization.
|
||||
|
||||
Policy (MVP):
|
||||
- Map bare "print"/"println" → "nyash.console.log"
|
||||
- Map "env.console.*" (println/log/print/warn/error) → "nyash.console.<method>"
|
||||
* println is normalized to log (pointer API).
|
||||
- Keep already-qualified "nyash.console.*" as-is, but normalize ...println → ...log
|
||||
|
||||
This module is imported by both instructions.externcall and instructions.mir_call
|
||||
to avoid duplication and drift.
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def normalize_extern_name(name: Optional[str]) -> str:
|
||||
if not name:
|
||||
return ""
|
||||
try:
|
||||
n = str(name)
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
try:
|
||||
if n.startswith("env.console."):
|
||||
method = n.split(".")[-1]
|
||||
if method == "println":
|
||||
method = "log"
|
||||
return f"nyash.console.{method}"
|
||||
if n in ("println", "print"):
|
||||
return "nyash.console.log"
|
||||
if n.startswith("nyash.console.") and n.endswith("println"):
|
||||
return "nyash.console.log"
|
||||
except Exception:
|
||||
# Fallthrough to original if anything odd happens
|
||||
pass
|
||||
return n
|
||||
|
||||
@ -6,6 +6,7 @@ Minimal mapping for NyRT-exported symbols (console/log family等)
|
||||
import llvmlite.ir as ir
|
||||
from typing import Dict, List, Optional, Any
|
||||
from instructions.safepoint import insert_automatic_safepoint
|
||||
from instructions.extern_normalize import normalize_extern_name
|
||||
|
||||
def lower_externcall(
|
||||
builder: ir.IRBuilder,
|
||||
@ -45,26 +46,17 @@ def lower_externcall(
|
||||
bb_map = ctx.bb_map
|
||||
except Exception:
|
||||
pass
|
||||
# Normalize extern target names
|
||||
# Accept full symbol names (e.g., "nyash.console.log", "nyash.string.len_h").
|
||||
# Also accept legacy/environment names and map them to kernel exports.
|
||||
llvm_name = func_name
|
||||
# Normalize extern target names through shared policy
|
||||
llvm_name = normalize_extern_name(func_name)
|
||||
# For C linkage, map dot-qualified console names to underscore symbols.
|
||||
# This keeps the logical name (nyash.console.log) stable at the MIR level
|
||||
# while emitting a C-friendly symbol (nyash_console_log) for linkage.
|
||||
c_symbol_name = llvm_name
|
||||
try:
|
||||
if func_name.startswith("env.console."):
|
||||
# Map env.console.* → nyash.console.* (kernel exports)
|
||||
method = func_name.split(".")[-1]
|
||||
# println maps to log for now
|
||||
if method == "println":
|
||||
method = "log"
|
||||
llvm_name = f"nyash.console.{method}"
|
||||
elif func_name == "println" or func_name == "print":
|
||||
# Bare println/print fallback
|
||||
llvm_name = "nyash.console.log"
|
||||
elif func_name.startswith("nyash.console.") and func_name.endswith("println"):
|
||||
# Normalize nyash.console.println → nyash.console.log
|
||||
llvm_name = "nyash.console.log"
|
||||
if llvm_name.startswith("nyash.console."):
|
||||
c_symbol_name = llvm_name.replace(".", "_")
|
||||
except Exception:
|
||||
pass
|
||||
c_symbol_name = llvm_name
|
||||
|
||||
i8 = ir.IntType(8)
|
||||
i64 = ir.IntType(64)
|
||||
@ -95,22 +87,22 @@ def lower_externcall(
|
||||
# Find or declare function with appropriate prototype
|
||||
func = None
|
||||
for f in module.functions:
|
||||
if f.name == llvm_name:
|
||||
if f.name == c_symbol_name:
|
||||
func = f
|
||||
break
|
||||
if not func:
|
||||
if llvm_name in sig_map:
|
||||
ret_ty, arg_tys = sig_map[llvm_name]
|
||||
fnty = ir.FunctionType(ret_ty, arg_tys)
|
||||
func = ir.Function(module, fnty, name=llvm_name)
|
||||
func = ir.Function(module, fnty, name=c_symbol_name)
|
||||
elif llvm_name.startswith("nyash.console."):
|
||||
# console.*: (i8*) -> i64
|
||||
fnty = ir.FunctionType(i64, [i8p])
|
||||
func = ir.Function(module, fnty, name=llvm_name)
|
||||
func = ir.Function(module, fnty, name=c_symbol_name)
|
||||
else:
|
||||
# Unknown extern: declare as void(...no args...) and call without args
|
||||
fnty = ir.FunctionType(void, [])
|
||||
func = ir.Function(module, fnty, name=llvm_name)
|
||||
func = ir.Function(module, fnty, name=c_symbol_name)
|
||||
|
||||
# Prepare/coerce arguments
|
||||
call_args: List[ir.Value] = []
|
||||
|
||||
@ -588,6 +588,10 @@ def lower_extern_call(builder, module, extern_name, args, dst_vid, vmap, resolve
|
||||
pass
|
||||
return vmap.get(vid)
|
||||
|
||||
# Normalize extern target names via shared normalizer
|
||||
from instructions.extern_normalize import normalize_extern_name
|
||||
extern_name = normalize_extern_name(extern_name)
|
||||
|
||||
# Look up extern function in module
|
||||
func = None
|
||||
for f in module.functions:
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
use super::*;
|
||||
use std::collections::HashMap;
|
||||
use crate::using::spec::{UsingPackage, PackageKind};
|
||||
use crate::using::ssot_bridge::{call_using_resolve_ssot, SsotCtx};
|
||||
|
||||
/// Using/module resolution context accumulated from config/env/nyash.toml
|
||||
pub(super) struct UsingContext {
|
||||
@ -129,6 +130,19 @@ pub(super) fn resolve_using_target(
|
||||
strict: bool,
|
||||
verbose: bool,
|
||||
) -> Result<String, String> {
|
||||
// Phase 22.1: Thin SSOT hook (future wiring). No behavior change for now.
|
||||
if std::env::var("HAKO_USING_SSOT").ok().as_deref() == Some("1")
|
||||
&& std::env::var("HAKO_USING_SSOT_INVOKING")
|
||||
.ok()
|
||||
.as_deref()
|
||||
!= Some("1")
|
||||
{
|
||||
if let Some(ssot_res) = try_resolve_using_target_ssot(
|
||||
tgt, is_path, modules, using_paths, aliases, packages, context_dir, strict, verbose,
|
||||
) {
|
||||
return Ok(ssot_res);
|
||||
}
|
||||
}
|
||||
// Invalidate and rebuild index/cache if env or nyash.toml changed
|
||||
super::box_index::rebuild_if_env_changed();
|
||||
if is_path {
|
||||
@ -330,6 +344,96 @@ pub(super) fn resolve_using_target(
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// Thin SSOT wrapper — returns Some(resolved) when an alternative SSOT path is available.
|
||||
/// MVP: return None to keep current behavior. Future: call into Hako `UsingResolveSSOTBox`.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn try_resolve_using_target_ssot(
|
||||
tgt: &str,
|
||||
is_path: bool,
|
||||
modules: &[(String, String)],
|
||||
using_paths: &[String],
|
||||
aliases: &HashMap<String, String>,
|
||||
packages: &HashMap<String, UsingPackage>,
|
||||
context_dir: Option<&std::path::Path>,
|
||||
strict: bool,
|
||||
verbose: bool,
|
||||
) -> Option<String> {
|
||||
// Phase 22.1 MVP: Build context and consult SSOT bridge (modules-only).
|
||||
let trace = verbose || crate::config::env::env_bool("NYASH_RESOLVE_TRACE");
|
||||
let mut map: HashMap<String, String> = HashMap::new();
|
||||
for (k, v) in modules {
|
||||
map.insert(k.clone(), v.clone());
|
||||
}
|
||||
let cwd_str = context_dir.and_then(|p| p.to_str()).map(|s| s.to_string());
|
||||
let ctx = SsotCtx { modules: map, using_paths: using_paths.to_vec(), cwd: cwd_str };
|
||||
if let Some(hit) = call_using_resolve_ssot(tgt, &ctx) {
|
||||
if trace {
|
||||
crate::runner::trace::log(format!("[using/ssot] '{}' -> '{}'", tgt, hit));
|
||||
}
|
||||
return Some(hit);
|
||||
}
|
||||
// Optional relative inference (Runner-side, guarded): prefer cwd > using_paths
|
||||
if std::env::var("HAKO_USING_SSOT_RELATIVE").ok().as_deref() == Some("1") {
|
||||
let rel_hako = tgt.replace('.', "/") + ".hako";
|
||||
let rel_ny = tgt.replace('.', "/") + ".nyash";
|
||||
let mut try_paths: Vec<std::path::PathBuf> = Vec::new();
|
||||
if let Some(dir) = context_dir {
|
||||
try_paths.push(dir.join(&rel_hako));
|
||||
try_paths.push(dir.join(&rel_ny));
|
||||
}
|
||||
for base in using_paths {
|
||||
let p = std::path::Path::new(base);
|
||||
try_paths.push(p.join(&rel_hako));
|
||||
try_paths.push(p.join(&rel_ny));
|
||||
}
|
||||
let mut found: Vec<String> = Vec::new();
|
||||
for p in try_paths {
|
||||
if p.exists() {
|
||||
found.push(p.to_string_lossy().to_string());
|
||||
}
|
||||
}
|
||||
if !found.is_empty() {
|
||||
if found.len() > 1 && strict {
|
||||
if trace {
|
||||
let total = found.len();
|
||||
// Allow customizing the number of shown candidates via env (bounded 1..=10)
|
||||
let n_show: usize = std::env::var("HAKO_USING_SSOT_RELATIVE_AMBIG_FIRST_N")
|
||||
.ok()
|
||||
.and_then(|s| s.parse::<usize>().ok())
|
||||
.map(|n| n.clamp(1, 10))
|
||||
.unwrap_or(3);
|
||||
let shown: Vec<String> = found.iter().take(n_show).cloned().collect();
|
||||
// Standardized message: count + first N + explicit delegation policy
|
||||
crate::runner::trace::log(format!(
|
||||
"[using/ssot:relative ambiguous] name='{}' count={} first=[{}] -> delegate=legacy(strict)",
|
||||
tgt,
|
||||
total,
|
||||
shown.join(", ")
|
||||
));
|
||||
}
|
||||
// Strict ambiguity: delegate to legacy resolver (behavior unchanged)
|
||||
} else {
|
||||
let out = found.remove(0);
|
||||
if trace {
|
||||
crate::runner::trace::log(format!(
|
||||
"[using/ssot:relative] '{}' -> '{}' (priority=cwd>using_paths)",
|
||||
tgt, out
|
||||
));
|
||||
}
|
||||
return Some(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fallback: keep parity by delegating to existing resolver within the same gate
|
||||
let prev = std::env::var("HAKO_USING_SSOT_INVOKING").ok();
|
||||
std::env::set_var("HAKO_USING_SSOT_INVOKING", "1");
|
||||
let res = resolve_using_target(
|
||||
tgt, is_path, modules, using_paths, aliases, packages, context_dir, strict, verbose,
|
||||
);
|
||||
if let Some(val) = prev { std::env::set_var("HAKO_USING_SSOT_INVOKING", val); } else { let _ = std::env::remove_var("HAKO_USING_SSOT_INVOKING"); }
|
||||
res.ok()
|
||||
}
|
||||
|
||||
/// Lint: enforce "fields must be at the top of box" rule.
|
||||
/// - Warns by default (when verbose); when `strict` is true, returns Err on any violation.
|
||||
pub(super) fn lint_fields_top(code: &str, strict: bool, verbose: bool) -> Result<(), String> {
|
||||
|
||||
@ -29,7 +29,53 @@ pub fn encode_args(args: &[Box<dyn NyashBox>]) -> Vec<u8> {
|
||||
encode::string(&mut buf, &a.to_string_box().value);
|
||||
}
|
||||
}
|
||||
buf
|
||||
maybe_tlv_roundtrip(buf)
|
||||
}
|
||||
|
||||
/// Optional TLV shim round‑trip (feature/env gated).
|
||||
///
|
||||
/// Behavior:
|
||||
/// - When compiled with feature `tlv-shim` AND env `HAKO_TLV_SHIM=1`,
|
||||
/// the encoded TLV buffer is passed through `nyash-tlv` identity round‑trip.
|
||||
/// - Otherwise, returns the original buffer unchanged.
|
||||
pub fn maybe_tlv_roundtrip(buf: Vec<u8>) -> Vec<u8> {
|
||||
if std::env::var("HAKO_TLV_SHIM").ok().as_deref() != Some("1") {
|
||||
return buf;
|
||||
}
|
||||
#[cfg(feature = "tlv-shim")]
|
||||
{
|
||||
return nyash_tlv::tlv_roundtrip_identity(&buf);
|
||||
}
|
||||
#[cfg(not(feature = "tlv-shim"))]
|
||||
{
|
||||
// Feature disabled: keep behavior identical
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn tlv_roundtrip_off_by_default() {
|
||||
std::env::remove_var("HAKO_TLV_SHIM");
|
||||
let src = vec![1u8, 2, 3, 4, 5];
|
||||
let out = maybe_tlv_roundtrip(src.clone());
|
||||
assert_eq!(out, src);
|
||||
}
|
||||
|
||||
#[cfg(feature = "tlv-shim")]
|
||||
#[test]
|
||||
fn tlv_roundtrip_env_feature_on() {
|
||||
std::env::set_var("HAKO_TLV_SHIM", "1");
|
||||
let src = vec![9u8, 8, 7, 6, 5, 4, 3];
|
||||
let out = maybe_tlv_roundtrip(src.clone());
|
||||
// Identity roundtrip returns the same bytes
|
||||
assert_eq!(out, src);
|
||||
// Cleanup
|
||||
std::env::remove_var("HAKO_TLV_SHIM");
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple helpers for common primitive returns
|
||||
|
||||
@ -17,6 +17,11 @@ pub fn extern_call(
|
||||
method_name: &str,
|
||||
args: &[Box<dyn NyashBox>],
|
||||
) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
if std::env::var("HAKO_CALL_TRACE").ok().as_deref() == Some("1") {
|
||||
if should_trace_call_extern(iface_name, method_name) {
|
||||
eprintln!("[call:{}.{}]", iface_name, method_name);
|
||||
}
|
||||
}
|
||||
match iface_name {
|
||||
"env.console" => handle_console(method_name, args),
|
||||
"env.result" => handle_result(method_name, args),
|
||||
@ -31,6 +36,19 @@ pub fn extern_call(
|
||||
}
|
||||
}
|
||||
|
||||
fn should_trace_call_extern(target: &str, method: &str) -> bool {
|
||||
if let Ok(flt) = std::env::var("HAKO_CALL_TRACE_FILTER") {
|
||||
let key = format!("{}.{}", target, method);
|
||||
for pat in flt.split(',') {
|
||||
let p = pat.trim();
|
||||
if p.is_empty() { continue; }
|
||||
if p == method || p == key { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Handle env.console.* methods
|
||||
fn handle_console(method_name: &str, args: &[Box<dyn NyashBox>]) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
match method_name {
|
||||
|
||||
@ -4,6 +4,7 @@ use crate::bid::{BidError, BidResult};
|
||||
use crate::box_trait::NyashBox;
|
||||
use crate::runtime::plugin_loader_v2::enabled::PluginLoaderV2;
|
||||
use std::sync::Arc;
|
||||
use std::env;
|
||||
|
||||
fn dbg_on() -> bool {
|
||||
std::env::var("PLUGIN_DEBUG").is_ok()
|
||||
@ -39,9 +40,60 @@ impl PluginLoaderV2 {
|
||||
let plugins = self.plugins.read().map_err(|_| BidError::PluginError)?;
|
||||
let _plugin = plugins.get(&lib_name).ok_or(BidError::PluginError)?;
|
||||
|
||||
// Optional C wrapper (Phase 22.2: design insertion point; default OFF)
|
||||
if env::var("HAKO_PLUGIN_LOADER_C_WRAP").ok().as_deref() == Some("1") {
|
||||
if should_trace_cwrap(box_type, method_name) {
|
||||
eprintln!("[cwrap:invoke:{}.{}]", box_type, method_name);
|
||||
}
|
||||
// Future: route into a thin C shim here. For now, fall through to normal path.
|
||||
}
|
||||
|
||||
// Optional C-core probe (design): emit tag and optionally call into c-core when enabled
|
||||
if env::var("HAKO_C_CORE_ENABLE").ok().as_deref() == Some("1") && should_route_ccore(box_type, method_name) {
|
||||
eprintln!("[c-core:invoke:{}.{}]", box_type, method_name);
|
||||
#[cfg(feature = "c-core")]
|
||||
{
|
||||
// MapBox.set: call C-core stub (no-op) with available info
|
||||
if box_type == "MapBox" && method_name == "set" {
|
||||
let key = args.get(0).map(|b| b.to_string_box().value).unwrap_or_default();
|
||||
let val = args.get(1).map(|b| b.to_string_box().value).unwrap_or_default();
|
||||
let _ = nyash_c_core::core_map_set(type_id as i32, instance_id, &key, &val);
|
||||
} else if box_type == "ArrayBox" && method_name == "push" {
|
||||
// For design stage, pass 0 (we don't rely on c-core result)
|
||||
let _ = nyash_c_core::core_array_push(type_id as i32, instance_id, 0);
|
||||
} else if box_type == "ArrayBox" && method_name == "get" {
|
||||
let _ = nyash_c_core::core_array_get(type_id as i32, instance_id, 0);
|
||||
} else if box_type == "ArrayBox" && (method_name == "size" || method_name == "len" || method_name == "length") {
|
||||
let _ = nyash_c_core::core_array_len(type_id as i32, instance_id);
|
||||
} else {
|
||||
// Generic probe
|
||||
let _ = nyash_c_core::core_probe_invoke(box_type, method_name, args.len() as i32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Encode TLV args via shared helper (numeric→string→toString)
|
||||
let tlv = crate::runtime::plugin_ffi_common::encode_args(args);
|
||||
|
||||
// Unified call trace (optional): plugin calls
|
||||
if env::var("HAKO_CALL_TRACE").ok().as_deref() == Some("1") {
|
||||
if should_trace_call(box_type, method_name) {
|
||||
eprintln!("[call:{}.{}]", box_type, method_name);
|
||||
}
|
||||
}
|
||||
|
||||
// Optional trace for TLV shim path (debug only; default OFF)
|
||||
if env::var("HAKO_TLV_SHIM_TRACE").ok().as_deref() == Some("1")
|
||||
&& env::var("HAKO_TLV_SHIM").ok().as_deref() == Some("1")
|
||||
{
|
||||
if should_trace_tlv_shim(box_type, method_name) {
|
||||
eprintln!("[tlv/shim:{}.{}]", box_type, method_name);
|
||||
if env::var("HAKO_TLV_SHIM_TRACE_DETAIL").ok().as_deref() == Some("1") {
|
||||
eprintln!("[tlv/shim:detail argc={}]", args.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if dbg_on() {
|
||||
eprintln!(
|
||||
"[PluginLoaderV2] call {}.{}: type_id={} method_id={} instance_id={}",
|
||||
@ -62,6 +114,63 @@ impl PluginLoaderV2 {
|
||||
}
|
||||
}
|
||||
|
||||
fn should_trace_tlv_shim(box_type: &str, method: &str) -> bool {
|
||||
// Filter provided → honor it
|
||||
if let Ok(flt) = env::var("HAKO_TLV_SHIM_FILTER") {
|
||||
let key = format!("{}.{}", box_type, method);
|
||||
for pat in flt.split(',') {
|
||||
let p = pat.trim();
|
||||
if p.is_empty() { continue; }
|
||||
if p == method || p == key { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Default (minimal noise): only trace MapBox.set to begin with
|
||||
box_type == "MapBox" && method == "set"
|
||||
}
|
||||
|
||||
fn should_trace_cwrap(box_type: &str, method: &str) -> bool {
|
||||
// Filter provided → honor it
|
||||
if let Ok(flt) = env::var("HAKO_PLUGIN_LOADER_C_WRAP_FILTER") {
|
||||
let key = format!("{}.{}", box_type, method);
|
||||
for pat in flt.split(',') {
|
||||
let p = pat.trim();
|
||||
if p.is_empty() { continue; }
|
||||
if p == method || p == key { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Default (minimal noise): only trace MapBox.set to begin with
|
||||
box_type == "MapBox" && method == "set"
|
||||
}
|
||||
|
||||
fn should_trace_call(target: &str, method: &str) -> bool {
|
||||
if let Ok(flt) = env::var("HAKO_CALL_TRACE_FILTER") {
|
||||
let key = format!("{}.{}", target, method);
|
||||
for pat in flt.split(',') {
|
||||
let p = pat.trim();
|
||||
if p.is_empty() { continue; }
|
||||
if p == method || p == key { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn should_route_ccore(box_type: &str, method: &str) -> bool {
|
||||
if let Ok(flt) = env::var("HAKO_C_CORE_TARGETS") {
|
||||
let key = format!("{}.{}", box_type, method);
|
||||
for pat in flt.split(',') {
|
||||
let p = pat.trim();
|
||||
if p.is_empty() { continue; }
|
||||
if p == method || p == key { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Default minimal scope: MapBox.set only
|
||||
box_type == "MapBox" && method == "set"
|
||||
}
|
||||
|
||||
/// Resolve type information for a box
|
||||
fn resolve_type_info(loader: &PluginLoaderV2, box_type: &str) -> BidResult<(String, u32)> {
|
||||
if let Some(cfg) = loader.config.as_ref() {
|
||||
@ -156,4 +265,4 @@ fn decode_tlv_result(box_type: &str, data: &[u8]) -> BidResult<Option<Box<dyn Ny
|
||||
return Ok(Some(bx));
|
||||
}
|
||||
Ok(Some(Box::new(crate::box_trait::VoidBox::new())))
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,3 +17,4 @@ pub mod spec;
|
||||
pub mod policy;
|
||||
pub mod errors;
|
||||
pub mod simple_registry;
|
||||
pub mod ssot_bridge;
|
||||
|
||||
107
src/using/ssot_bridge.rs
Normal file
107
src/using/ssot_bridge.rs
Normal file
@ -0,0 +1,107 @@
|
||||
//! SSOT bridge — thin callable shim from Rust to Hako resolver (Phase 22.1)
|
||||
//!
|
||||
//! MVP: does not invoke Hako VM yet. It mirrors the Hako box logic for modules-only
|
||||
//! resolution, returning the mapped path when present. Callers must keep behavior
|
||||
//! identical to existing resolver and use this only under an explicit env toggle.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::io::Write;
|
||||
use std::process::Command;
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct SsotCtx {
|
||||
pub modules: HashMap<String, String>,
|
||||
pub using_paths: Vec<String>,
|
||||
pub cwd: Option<String>,
|
||||
}
|
||||
|
||||
/// Attempt to resolve via SSOT bridge. Returns Some(path) if found; otherwise None.
|
||||
///
|
||||
/// Behavior (MVP):
|
||||
/// - Only consults `modules` map (exact match).
|
||||
/// - Does not access filesystem nor invoke Hako VM.
|
||||
pub fn call_using_resolve_ssot(name: &str, ctx: &SsotCtx) -> Option<String> {
|
||||
if name.is_empty() { return None; }
|
||||
// Optional: delegate to Hako resolver when explicitly requested.
|
||||
if std::env::var("HAKO_USING_SSOT_HAKO").ok().as_deref() == Some("1") {
|
||||
if let Some(hit) = call_hako_box(name, ctx) { return Some(hit); }
|
||||
}
|
||||
// MVP: modules-only
|
||||
ctx.modules.get(name).cloned()
|
||||
}
|
||||
|
||||
/// Try resolving via Hako `UsingResolveSSOTBox.resolve(name, ctx)` by spawning the nyash VM.
|
||||
/// Guarded by `HAKO_USING_SSOT_HAKO=1`. Returns Some(path) on success; otherwise None.
|
||||
fn call_hako_box(name: &str, ctx: &SsotCtx) -> Option<String> {
|
||||
// Build inline Hako code that constructs a minimal ctx with modules map.
|
||||
let mut code = String::new();
|
||||
code.push_str("using hako.using.resolve.ssot as UsingResolveSSOTBox\n");
|
||||
code.push_str("static box Main {\n main() {\n local modules = new MapBox()\n");
|
||||
for (k, v) in ctx.modules.iter() {
|
||||
// Escape quotes conservatively
|
||||
let kk = k.replace('\"', "\\\"");
|
||||
let vv = v.replace('\"', "\\\"");
|
||||
code.push_str(&format!(" modules.set(\"{}\", \"{}\")\n", kk, vv));
|
||||
}
|
||||
code.push_str(" local ctx = new MapBox()\n ctx.set(\"modules\", modules)\n");
|
||||
// relative_hint: opt-in via parent env HAKO_USING_SSOT_RELATIVE=1
|
||||
if std::env::var("HAKO_USING_SSOT_RELATIVE").ok().as_deref() == Some("1") {
|
||||
code.push_str(" ctx.set(\\\"relative_hint\\\", \\\"1\\\")\\n");
|
||||
}
|
||||
// using_paths
|
||||
if !ctx.using_paths.is_empty() {
|
||||
code.push_str(" local ups = new ArrayBox()\n");
|
||||
for up in ctx.using_paths.iter() {
|
||||
let upq = up.replace('\"', "\\\"");
|
||||
code.push_str(&format!(" ups.push(\"{}\")\n", upq));
|
||||
}
|
||||
code.push_str(" ctx.set(\\\"using_paths\\\", ups)\n");
|
||||
}
|
||||
// cwd
|
||||
if let Some(cwd) = &ctx.cwd {
|
||||
let cwq = cwd.replace('\"', "\\\"");
|
||||
code.push_str(&format!(" ctx.set(\\\"cwd\\\", \"{}\")\n", cwq));
|
||||
}
|
||||
let nn = name.replace('\"', "\\\"");
|
||||
code.push_str(&format!(
|
||||
" local r = UsingResolveSSOTBox.resolve(\"{}\", ctx)\n if r == null {{ return 0 }}\n print(r)\n return 0\n }}\n",
|
||||
nn
|
||||
));
|
||||
|
||||
// Write to a temp file
|
||||
// Write ephemeral file; any failure → None (delegate to legacy)
|
||||
let mut tf = tempfile::Builder::new()
|
||||
.prefix("ny_ssot_")
|
||||
.suffix(".hako")
|
||||
.tempfile()
|
||||
.ok()?;
|
||||
let _ = write!(tf, "{}", code);
|
||||
let path = tf.path().to_path_buf();
|
||||
// Resolve nyash binary; fallback to current exe or default path on failure
|
||||
let bin = std::env::var("NYASH_BIN").ok().unwrap_or_else(|| {
|
||||
if let Ok(p) = std::env::current_exe() { p.to_string_lossy().to_string() }
|
||||
else { "target/release/nyash".to_string() }
|
||||
});
|
||||
|
||||
// Stage‑3 + tolerance (matches smokes wrappers)
|
||||
let mut cmd = Command::new(bin);
|
||||
cmd.arg("--backend").arg("vm").arg(&path)
|
||||
// Parser/entry tolerances (same as smokes "safe" mode)
|
||||
.env("NYASH_PARSER_STAGE3", "1")
|
||||
.env("HAKO_PARSER_STAGE3", "1")
|
||||
.env("NYASH_PARSER_ALLOW_SEMICOLON", "1")
|
||||
.env("NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN", "1")
|
||||
// Disable inline compiler for stability
|
||||
.env("NYASH_DISABLE_NY_COMPILER", "1")
|
||||
.env("HAKO_DISABLE_NY_COMPILER", "1")
|
||||
// Hard-disable SSOT in the child to avoid recursion; mark invoking guard
|
||||
.env("HAKO_USING_SSOT", "0")
|
||||
.env("HAKO_USING_SSOT_HAKO", "0")
|
||||
.env("HAKO_USING_SSOT_RELATIVE", "0")
|
||||
.env("HAKO_USING_SSOT_INVOKING", "1");
|
||||
// Any spawn/IO error → None (fail-safe to legacy)
|
||||
let out = cmd.output().ok()?;
|
||||
if !out.status.success() { return None; }
|
||||
let s = String::from_utf8_lossy(&out.stdout).trim().to_string();
|
||||
if s.is_empty() { None } else { Some(s) }
|
||||
}
|
||||
@ -53,7 +53,8 @@ fi
|
||||
|
||||
# 2) Emit + link compiler.hako → EXE
|
||||
echo "[2/4] Emitting + linking selfhost compiler ..."
|
||||
tools/build_llvm.sh apps/selfhost/compiler/compiler.hako -o "$OUT"
|
||||
# SSOT: compiler entry is under lang/src/compiler/entry/compiler.hako
|
||||
tools/build_llvm.sh lang/src/compiler/entry/compiler.hako -o "$OUT"
|
||||
|
||||
if [[ "$PACK" == "0" ]]; then
|
||||
echo "✅ Built: ./$OUT"
|
||||
|
||||
120
tools/hakorune_emit_mir.sh
Normal file
120
tools/hakorune_emit_mir.sh
Normal file
@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env bash
|
||||
# hakorune_emit_mir.sh — Emit MIR(JSON) using Hakorune Stage‑B + MirBuilder (Hako‑first)
|
||||
#
|
||||
# Usage: tools/hakorune_emit_mir.sh <input.hako> <out.json>
|
||||
# Notes:
|
||||
# - Runs the Stage‑B compiler (Hako) to emit Program(JSON v0), then feeds it to MirBuilderBox.emit_from_program_json_v0.
|
||||
# - Defaults to the Hakorune VM path; no inline Ny compiler; Stage‑3 enabled.
|
||||
# - Keeps defaults conservative: no global flips; this is a helper for dev/CI scripts.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [ "$#" -ne 2 ]; then
|
||||
echo "Usage: $0 <input.hako> <out.json>" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
IN="$1"
|
||||
OUT="$2"
|
||||
|
||||
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
|
||||
|
||||
# Resolve nyash/hakorune binary via test_runner helper (ensures consistent env)
|
||||
if [ ! -f "$IN" ]; then
|
||||
echo "[FAIL] input not found: $IN" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Resolve nyash/hakorune binary (simple detection; test_runner will override later if sourced)
|
||||
if [ -z "${NYASH_BIN:-}" ]; then
|
||||
if [ -x "$ROOT/target/release/hakorune" ]; then
|
||||
export NYASH_BIN="$ROOT/target/release/hakorune"
|
||||
else
|
||||
export NYASH_BIN="$ROOT/target/release/nyash"
|
||||
fi
|
||||
fi
|
||||
|
||||
CODE="$(cat "$IN")"
|
||||
|
||||
# 1) Stage‑B: Hako parser emits Program(JSON v0) to stdout
|
||||
set +e
|
||||
PROG_JSON_OUT=$(NYASH_DISABLE_NY_COMPILER=1 HAKO_DISABLE_NY_COMPILER=1 \
|
||||
NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 NYASH_PARSER_ALLOW_SEMICOLON=1 \
|
||||
NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \
|
||||
"$NYASH_BIN" --backend vm "$ROOT/lang/src/compiler/entry/compiler_stageb.hako" -- --source "$CODE" 2>/dev/null)
|
||||
rc=$?
|
||||
set -e
|
||||
if [ $rc -ne 0 ] || [ -z "$PROG_JSON_OUT" ]; then
|
||||
echo "[FAIL] Stage-B parse failed (rc=$rc)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Quick validation for Program(JSON v0)
|
||||
if ! printf '%s' "$PROG_JSON_OUT" | grep -q '"kind"\s*:\s*"Program"'; then
|
||||
echo "[FAIL] Stage‑B output is not Program(JSON)" >&2
|
||||
printf '%s\n' "$PROG_JSON_OUT" | sed -n '1,80p' >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 2) Hako MirBuilder: convert Program(JSON v0) → MIR(JSON)
|
||||
BUILDER_CODE=$(cat <<'HCODE'
|
||||
using "hako.mir.builder" as MirBuilderBox
|
||||
static box Main { method main(args) {
|
||||
local prog_json = env.get("HAKO_BUILDER_PROGRAM_JSON")
|
||||
if prog_json == null { print("Builder failed"); return 1 }
|
||||
local mir_out = MirBuilderBox.emit_from_program_json_v0(prog_json, null)
|
||||
if mir_out == null { print("Builder failed"); return 1 }
|
||||
print("[MIR_OUT_BEGIN]")
|
||||
print("" + mir_out)
|
||||
print("[MIR_OUT_END]")
|
||||
return 0
|
||||
} }
|
||||
HCODE
|
||||
)
|
||||
|
||||
# Use the smoke test runner to execute builder code inline (-c), ensuring consistent parser/env setup
|
||||
source "$ROOT/tools/smokes/v2/lib/test_runner.sh" >/dev/null 2>&1 || true
|
||||
require_env >/dev/null 2>&1 || true
|
||||
tmp_stdout="/tmp/hako_builder_out_$$.log"
|
||||
tmp_stderr="/tmp/hako_builder_err_$$.log"
|
||||
trap 'rm -f "$tmp_stdout" "$tmp_stderr" || true' EXIT
|
||||
|
||||
set +e
|
||||
MIR_JSON=$(HAKO_MIR_BUILDER_INTERNAL=1 HAKO_MIR_BUILDER_REGISTRY=1 \
|
||||
HAKO_MIR_BUILDER_DEBUG=${HAKO_MIR_BUILDER_DEBUG:-0} \
|
||||
HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 \
|
||||
HAKO_ROUTE_HAKOVM=1 \
|
||||
NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \
|
||||
NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \
|
||||
NYASH_PARSER_SEAM_TOLERANT=1 \
|
||||
NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=0 HAKO_PARSER_STAGE3=0 \
|
||||
NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \
|
||||
HAKO_BUILDER_PROGRAM_JSON="$PROG_JSON_OUT" \
|
||||
run_nyash_vm -c "$BUILDER_CODE" 2>"$tmp_stderr" | tee "$tmp_stdout" | awk '/\[MIR_OUT_BEGIN\]/{flag=1;next}/\[MIR_OUT_END\]/{flag=0}flag')
|
||||
rc=$?
|
||||
set -e
|
||||
|
||||
if [ $rc -ne 0 ] || [ -z "$MIR_JSON" ] || ! printf '%s' "$MIR_JSON" | grep -q '"functions"'; then
|
||||
echo "[WARN] MirBuilder (Hako) failed (rc=$rc), falling back to Rust CLI builder" >&2
|
||||
# Use runner CLI to convert Program(JSON) → MIR(JSON)
|
||||
tmp_prog="/tmp/hako_emit_prog_$$.json"
|
||||
printf '%s' "$PROG_JSON_OUT" > "$tmp_prog"
|
||||
if "$NYASH_BIN" --program-json-to-mir "$OUT" --json-file "$tmp_prog" >/dev/null 2>&1; then
|
||||
rm -f "$tmp_prog" || true
|
||||
echo "[OK] MIR JSON written (delegate): $OUT"
|
||||
exit 0
|
||||
fi
|
||||
echo "[FAIL] Both Hako builder and delegate failed" >&2
|
||||
echo "-- stderr (tail) --" >&2; tail -n 80 "$tmp_stderr" >&2 || true
|
||||
echo "-- stdout (tail) --" >&2; tail -n 80 "$tmp_stdout" >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf '%s' "$MIR_JSON" > "$OUT"
|
||||
echo "[OK] MIR JSON written: $OUT"
|
||||
exit 0
|
||||
@ -24,6 +24,7 @@ TARGET=""
|
||||
NYRT_DIR=""
|
||||
VERIFY=0
|
||||
QUIET=0
|
||||
BACKEND="${NYASH_LLVM_BACKEND:-llvmlite}" # llvmlite | crate | native (reserved)
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
@ -68,6 +69,10 @@ if [[ "$SKIP_BUILD" != "1" ]]; then
|
||||
else
|
||||
timeout "$BUILD_TIMEOUT" cargo build --release -j 24 --features "${LLVM_FEATURE}" >/dev/null
|
||||
fi
|
||||
# Prebuild ny-llvmc when using crate backend
|
||||
if [[ "$BACKEND" == "crate" ]]; then
|
||||
(cd "$(dirname "$0")/.." && timeout "$BUILD_TIMEOUT" cargo build --release -j 24 -p nyash-llvm-compiler >/dev/null) || true
|
||||
fi
|
||||
if [[ "$EMIT" == "exe" ]]; then
|
||||
(cd crates/nyrt && timeout "$BUILD_TIMEOUT" cargo build --release -j 24 >/dev/null)
|
||||
fi
|
||||
@ -112,11 +117,23 @@ case "$EMIT" in
|
||||
[[ "$QUIET" == "0" ]] && echo "OK ll:$OUT"
|
||||
;;
|
||||
obj)
|
||||
# Directly use llvmlite harness with MIR v1 JSON input
|
||||
rm -f "$OUT"
|
||||
if ! python3 "$PWD/tools/llvmlite_harness.py" --in "$IN_FILE" --out "$OUT" >/dev/null 2>&1; then
|
||||
echo "error: harness failed to produce $OUT" >&2; exit 4
|
||||
fi
|
||||
case "$BACKEND" in
|
||||
crate)
|
||||
BIN_NYLLVMC="./target/release/ny-llvmc"
|
||||
if [[ ! -x "$BIN_NYLLVMC" ]]; then
|
||||
echo "error: ny-llvmc not found (cargo build -p nyash-llvm-compiler)" >&2; exit 4
|
||||
fi
|
||||
rm -f "$OUT"
|
||||
"$BIN_NYLLVMC" --in "$IN_FILE" --emit obj --out "$OUT" >/dev/null 2>&1 || { echo "error: ny-llvmc failed" >&2; exit 4; }
|
||||
;;
|
||||
llvmlite|*)
|
||||
# Directly use llvmlite harness with MIR v1 JSON input
|
||||
rm -f "$OUT"
|
||||
if ! python3 "$PWD/tools/llvmlite_harness.py" --in "$IN_FILE" --out "$OUT" >/dev/null 2>&1; then
|
||||
echo "error: harness failed to produce $OUT" >&2; exit 4
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
if [[ ! -f "$OUT" ]]; then echo "error: failed to produce $OUT" >&2; exit 4; fi
|
||||
[[ "$QUIET" == "0" ]] && echo "OK obj:$OUT"
|
||||
;;
|
||||
@ -124,17 +141,32 @@ case "$EMIT" in
|
||||
# Emit obj then link
|
||||
OBJ="$PWD/target/aot_objects/__tmp_builder.o"
|
||||
rm -f "$OBJ"
|
||||
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
|
||||
fi
|
||||
if [[ ! -f "$OBJ" ]]; then echo "error: failed to produce object $OBJ" >&2; exit 4; fi
|
||||
# Link with NyRT
|
||||
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"
|
||||
case "$BACKEND" in
|
||||
crate)
|
||||
BIN_NYLLVMC="./target/release/ny-llvmc"
|
||||
if [[ ! -x "$BIN_NYLLVMC" ]]; then
|
||||
echo "error: ny-llvmc not found (cargo build -p nyash-llvm-compiler)" >&2; exit 4
|
||||
fi
|
||||
# Produce exe directly via ny-llvmc (lets ny-llvmc link)
|
||||
LIBS="${HAKO_AOT_LDFLAGS:-}"
|
||||
if ! "$BIN_NYLLVMC" --in "$IN_FILE" --emit exe --nyrt target/release --libs "$LIBS" --out "$OUT" >/dev/null 2>&1; then
|
||||
echo "error: ny-llvmc failed to link exe" >&2; exit 4
|
||||
fi
|
||||
;;
|
||||
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
|
||||
fi
|
||||
if [[ ! -f "$OBJ" ]]; then echo "error: failed to produce object $OBJ" >&2; exit 4; fi
|
||||
# Link with NyRT
|
||||
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"
|
||||
;;
|
||||
esac
|
||||
[[ "$QUIET" == "0" ]] && echo "OK exe:$OUT"
|
||||
;;
|
||||
*) echo "error: invalid emit kind: $EMIT" >&2; exit 2 ;;
|
||||
|
||||
19
tools/selfhost/examples/gen_v1_print_hello.sh
Normal file
19
tools/selfhost/examples/gen_v1_print_hello.sh
Normal file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
# gen_v1_print_hello.sh — Minimal v1 JSON that extern-calls print("hello") then returns 0
|
||||
set -euo pipefail
|
||||
cat <<'JSON'
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"functions": [
|
||||
{"name": "main", "params": [], "blocks": [
|
||||
{"id": 0, "instructions": [
|
||||
{"op":"const","dst":1,"value":{"type":"string","value":"hello"}},
|
||||
{"op":"externcall","func":"print","args":[1]},
|
||||
{"op":"const","dst":2,"value":{"type":"i64","value":0}},
|
||||
{"op":"ret","value":2}
|
||||
]}
|
||||
]}
|
||||
]
|
||||
}
|
||||
JSON
|
||||
|
||||
@ -17,4 +17,4 @@ HCODE
|
||||
|
||||
NYASH_USING_AST=1 NYASH_DISABLE_NY_COMPILER=1 HAKO_DISABLE_NY_COMPILER=1 \
|
||||
NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 NYASH_PARSER_ALLOW_SEMICOLON=1 \
|
||||
run_nyash_vm -c "$code" 2>/dev/null | tr -d '\r'
|
||||
NYASH_JSON_ONLY=1 run_nyash_vm -c "$code" 2>/dev/null | tr -d '\r'
|
||||
|
||||
@ -19,5 +19,4 @@ HCODE
|
||||
NYASH_USING_PROFILE=dev NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \
|
||||
NYASH_DISABLE_NY_COMPILER=1 HAKO_DISABLE_NY_COMPILER=1 \
|
||||
NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 NYASH_PARSER_ALLOW_SEMICOLON=1 \
|
||||
run_nyash_vm -c "$code" 2>/dev/null | tr -d '\r'
|
||||
|
||||
NYASH_JSON_ONLY=1 run_nyash_vm -c "$code" 2>/dev/null | tr -d '\r'
|
||||
|
||||
@ -61,20 +61,30 @@ log_error() {
|
||||
|
||||
# 共通ノイズフィルタ(VM実行時の出力整形)
|
||||
filter_noise() {
|
||||
if [ "${HAKO_SHOW_CALL_LOGS:-0}" = "1" ]; then
|
||||
# Show raw logs (no filtering) to allow call traces / diagnostics
|
||||
cat
|
||||
return
|
||||
fi
|
||||
# プラグイン初期化やメタログ、動的ローダの案内等を除去
|
||||
grep -v "^\[UnifiedBoxRegistry\]" \
|
||||
| grep -v "^\[FileBox\]" \
|
||||
| grep -v "^\[provider-registry\]" \
|
||||
| grep -v "^\[plugin/missing\]" \
|
||||
| grep -v "^\[plugin/hint\]" \
|
||||
| grep -v "^Net plugin:" \
|
||||
| grep -v "^\[.*\] Plugin" \
|
||||
| grep -v "^\[.*\] Plugin" \
|
||||
| grep -v "Using builtin StringBox" \
|
||||
| grep -v "Using builtin ArrayBox" \
|
||||
| grep -v "Using builtin MapBox" \
|
||||
| grep -v "^\[using\]" \
|
||||
| grep -v "^\[using/resolve\]" \
|
||||
| grep -v "^\[using/text-merge\]" \
|
||||
| grep -v "^\[builder\]" \
|
||||
| grep -v "^\\[vm-trace\\]" \
|
||||
| grep -v "^\[vm\] Stage-3" \
|
||||
| grep -v "^\[DEBUG\]" \
|
||||
| grep -v '^\{"ev":' \
|
||||
| grep -v '^\{"ev":' \
|
||||
| grep -v '^\[warn\]' \
|
||||
| grep -v '^\[error\]' \
|
||||
| grep -v '^\[warn\] dev fallback: user instance BoxCall' \
|
||||
@ -176,6 +186,7 @@ run_nyash_vm() {
|
||||
# Enable with: SMOKES_CLEAN_ENV=1
|
||||
local ENV_PREFIX=( )
|
||||
if [ "${SMOKES_CLEAN_ENV:-0}" = "1" ]; then
|
||||
# Preserve NYASH_JSON_ONLY to allow quiet JSON pipelines (e.g., v1 emitters)
|
||||
ENV_PREFIX=(env -u NYASH_DEBUG_ENABLE -u NYASH_DEBUG_KINDS -u NYASH_DEBUG_SINK \
|
||||
-u NYASH_RESOLVE_FIX_BRACES -u NYASH_USING_AST \
|
||||
-u NYASH_VM_TRACE -u NYASH_VM_VERIFY_MIR -u NYASH_VM_TOLERATE_VOID \
|
||||
@ -759,8 +770,15 @@ v1_normalized_hash() {
|
||||
echo "[FAIL] v1_normalized_hash: jq required" >&2
|
||||
return 2
|
||||
fi
|
||||
# Extract JSON object line defensively (strip any leading noise like 'RC: N' or logs)
|
||||
# Extract JSON object block from first '{' to EOF (handles pretty JSON)
|
||||
local raw_json
|
||||
raw_json=$(awk 'BEGIN{on=0} { if(on){print} else if($0 ~ /^[[:space:]]*\{/){ on=1; print } }' "$json_path")
|
||||
if [ -z "$raw_json" ]; then
|
||||
return 1
|
||||
fi
|
||||
local canon
|
||||
canon=$(jq -S -c . < "$json_path") || return 1
|
||||
canon=$(printf '%s' "$raw_json" | jq -S -c .) || return 1
|
||||
printf "%s" "$canon" | sha256sum | awk '{print $1}'
|
||||
}
|
||||
|
||||
@ -785,13 +803,19 @@ verify_v1_inline_file() {
|
||||
local out
|
||||
# Optional: show full logs for debugging (default OFF)
|
||||
if [ "${HAKO_VERIFY_SHOW_LOGS:-0}" = "1" ]; then
|
||||
# Show all output to stderr, then extract numeric rc
|
||||
HAKO_ROUTE_HAKOVM=1 HAKO_VERIFY_V1_FORCE_HAKOVM=1 NYASH_VERIFY_JSON="$(cat "$json_path")" \
|
||||
# Show all output to stderr, then extract numeric rc (env-sanitized for determinism)
|
||||
env -i PATH="$PATH" \
|
||||
HAKO_TRACE_EXECUTION="${HAKO_TRACE_EXECUTION:-0}" HAKO_VERIFY_SHOW_LOGS="${HAKO_VERIFY_SHOW_LOGS:-0}" \
|
||||
HAKO_ROUTE_HAKOVM=1 HAKO_VERIFY_V1_FORCE_HAKOVM=1 \
|
||||
NYASH_VERIFY_JSON="$(cat "$json_path")" \
|
||||
"$NYASH_BIN" --backend vm /dev/null 2>&1 | tr -d '\r' | tee /tmp/hv1_debug.log >&2
|
||||
out=$(awk '/^-?[0-9]+$/{n=$0} END{if(n!="") print n}' /tmp/hv1_debug.log)
|
||||
else
|
||||
out=$(HAKO_ROUTE_HAKOVM=1 HAKO_VERIFY_V1_FORCE_HAKOVM=1 NYASH_VERIFY_JSON="$(cat "$json_path")" \
|
||||
"$NYASH_BIN" --backend vm /dev/null 2>/dev/null | tr -d '\r' | awk '/^-?[0-9]+$/{n=$0} END{if(n!="") print n}')
|
||||
out=$(env -i PATH="$PATH" \
|
||||
HAKO_TRACE_EXECUTION="${HAKO_TRACE_EXECUTION:-0}" \
|
||||
HAKO_ROUTE_HAKOVM=1 HAKO_VERIFY_V1_FORCE_HAKOVM=1 \
|
||||
NYASH_VERIFY_JSON="$(cat "$json_path")" \
|
||||
"$NYASH_BIN" --backend vm /dev/null 2>/dev/null | tr -d '\r' | awk '/^-?[0-9]+$/{n=$0} END{if(n!="") print n}')
|
||||
fi
|
||||
if [[ "$out" =~ ^-?[0-9]+$ ]]; then
|
||||
# echo numeric rc and return success; caller normalizes/returns as exit code
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
# S3: externcall print("hello") → link + run (rc=0)
|
||||
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
|
||||
|
||||
if [ "${NYASH_LLVM_S3:-auto}" = "0" ]; then
|
||||
echo "[SKIP] s3_link_run_llvmlite_print_canary_vm (NYASH_LLVM_S3=0)" >&2
|
||||
exit 0
|
||||
fi
|
||||
if ! command -v llvm-config-18 >/dev/null 2>&1; then
|
||||
echo "[SKIP] s3_link_run_llvmlite_print_canary_vm (LLVM18 not available)" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
json=$(bash "$ROOT/tools/selfhost/examples/gen_v1_print_hello.sh")
|
||||
tmp_json="/tmp/s3_v1_print_$$.json"; printf '%s' "$json" > "$tmp_json"
|
||||
exe="/tmp/s3_exe_print_$$"
|
||||
|
||||
set +e
|
||||
out=$(NYASH_LLVM_SKIP_BUILD=${NYASH_LLVM_SKIP_BUILD:-1} \
|
||||
bash "$ROOT/tools/ny_mir_builder.sh" --in "$tmp_json" --emit exe -o "$exe" 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
if [ "$rc" -ne 0 ] || [ ! -x "$exe" ]; then
|
||||
echo "[FAIL] s3_link_run_llvmlite_print_canary_vm (builder rc=$rc)" >&2
|
||||
printf '%s\n' "$out" | sed -n '1,200p' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set +e
|
||||
"$exe" >/dev/null 2>&1
|
||||
erc=$?
|
||||
set -e
|
||||
if [ "$erc" -ne 0 ]; then
|
||||
echo "[FAIL] s3_link_run_llvmlite_print_canary_vm (exit=$erc, expect 0)" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "[PASS] s3_link_run_llvmlite_print_canary_vm"
|
||||
exit 0
|
||||
|
||||
@ -7,6 +7,10 @@ source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2
|
||||
|
||||
tmp="/tmp/selfhost_v1_$$.json"
|
||||
bash "$ROOT/tools/selfhost/gen_v1_from_selfhost_pipeline_min.sh" > "$tmp"
|
||||
if [ "${HAKO_VERIFY_SHOW_LOGS:-0}" = "1" ]; then
|
||||
echo "[debug] hv1 input json at: $tmp" >&2
|
||||
head -n 2 "$tmp" >&2 || true
|
||||
fi
|
||||
|
||||
set +e
|
||||
rc=$(HAKO_PRIMARY_NO_FALLBACK=1 HAKO_VERIFY_PRIMARY=hakovm verify_v1_inline_file "$tmp" || true)
|
||||
@ -19,4 +23,3 @@ if [[ "$rc" =~ ^-?[0-9]+$ ]] && [ "$rc" -eq 42 ]; then
|
||||
fi
|
||||
echo "[FAIL] selfhost_v1_primary_rc42_canary_vm (rc=$rc, expect 42)" >&2
|
||||
exit 1
|
||||
|
||||
|
||||
@ -3,13 +3,19 @@ set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||
|
||||
echo "[phase2100] S1/S2 (v1) repeat determinism..."
|
||||
# Layer 1: 軽量セルフホスト・カナリア(常時・LLVM不要)
|
||||
bash "$ROOT/tools/smokes/v2/run.sh" --profile quick --filter 'phase2100/selfhost_canary_minimal.sh'
|
||||
bash "$ROOT/tools/smokes/v2/run.sh" --profile quick --filter 'phase2048/s1s2s3_repeat_const_canary_vm.sh'
|
||||
bash "$ROOT/tools/smokes/v2/run.sh" --profile quick --filter 'phase2048/s1s2s3_repeat_compare_cfg_canary_vm.sh'
|
||||
bash "$ROOT/tools/smokes/v2/run.sh" --profile quick --filter 'phase2048/s1s2s3_repeat_threeblock_collect_canary_vm.sh'
|
||||
|
||||
echo "[phase2100] PRIMARY (hv1 inline) — selfhost v1 minimal (Option A/B)..."
|
||||
bash "$ROOT/tools/smokes/v2/run.sh" --profile quick --filter 'phase2051/selfhost_v1_primary_rc42_canary_vm.sh'
|
||||
bash "$ROOT/tools/smokes/v2/run.sh" --profile quick --filter 'phase2051/selfhost_v1_provider_primary_rc42_canary_vm.sh'
|
||||
if [[ "${HAKO_PHASE2100_ENABLE_HV1:-1}" == "1" ]]; then
|
||||
echo "[phase2100] PRIMARY (hv1 inline) — selfhost v1 minimal (Option A/B)..."
|
||||
bash "$ROOT/tools/smokes/v2/run.sh" --profile quick --filter 'phase2051/selfhost_v1_primary_rc42_canary_vm.sh'
|
||||
bash "$ROOT/tools/smokes/v2/run.sh" --profile quick --filter 'phase2051/selfhost_v1_provider_primary_rc42_canary_vm.sh'
|
||||
else
|
||||
echo "[phase2100] Skipping hv1 inline PRIMARY (default). Set HAKO_PHASE2100_ENABLE_HV1=1 to run."
|
||||
fi
|
||||
|
||||
# Decide S3 policy: auto-enable when LLVM18 is present unless user forces off
|
||||
if [[ -z "${NYASH_LLVM_S3:-}" ]]; then
|
||||
@ -47,4 +53,15 @@ else
|
||||
echo "[phase2100] Skipping S3 (auto-disabled; export NYASH_LLVM_S3=1 to force)"
|
||||
fi
|
||||
|
||||
# Optional: Selfhost EXE-first smoke (heavy). Disabled by default.
|
||||
if [[ "${SMOKES_ENABLE_SELFHOST:-0}" == "1" ]]; then
|
||||
if command -v llvm-config-18 >/dev/null 2>&1; then
|
||||
echo "[phase2100] Selfhost EXE-first smokes (opt-in)..."
|
||||
timeout 300 bash "$ROOT/tools/exe_first_smoke.sh"
|
||||
timeout 300 bash "$ROOT/tools/exe_first_runner_smoke.sh"
|
||||
else
|
||||
echo "[phase2100] SKIP selfhost EXE-first (LLVM18 not available)" >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "[phase2100] Done."
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||
|
||||
# Prebuild ny-llvmc and nyash_kernel (NyRT)
|
||||
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null)
|
||||
(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null)
|
||||
|
||||
APP="/tmp/ny_crate_backend_exe_$$"
|
||||
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
||||
|
||||
if "$BIN_NYLLVMC" --dummy --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
||||
if [[ -x "$APP" ]]; then
|
||||
set +e
|
||||
"$APP"
|
||||
rc=$?
|
||||
set -e
|
||||
if [ "$rc" -eq 0 ]; then
|
||||
echo "[PASS] s3_backend_selector_crate_exe_canary_vm"
|
||||
rm -f "$APP" 2>/dev/null || true
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
echo "[FAIL] s3_backend_selector_crate_exe_canary_vm" >&2
|
||||
exit 1
|
||||
|
||||
@ -0,0 +1,49 @@
|
||||
#!/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
|
||||
# Build minimal C runtime (design-stage) to provide nyash_console_log
|
||||
(cd "$ROOT" && cargo build -q --release -p nyash-kernel-min-c >/dev/null) || true
|
||||
|
||||
# Minimal MIR v1 JSON that intends to print then return 0.
|
||||
# Note: If the builder rejects schema, we SKIP gracefully.
|
||||
JSON='{
|
||||
"schema_version": 1,
|
||||
"functions": [
|
||||
{"name":"ny_main","blocks":[
|
||||
{"id":0,"inst":[
|
||||
{"op":"const","dst":1,"ty":"i64","value":0},
|
||||
{"op":"externcall","func":"nyash.console.log","args":[1]},
|
||||
{"op":"ret","value":1}
|
||||
]}
|
||||
]}
|
||||
]
|
||||
}'
|
||||
|
||||
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"
|
||||
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 [[ -x "$APP" ]]; then
|
||||
set +e
|
||||
out="$($APP 2>/dev/null)"; rc=$?
|
||||
set -e
|
||||
if [ "$rc" -eq 0 ] && echo "$out" | grep -q '^hello$'; then
|
||||
echo "[PASS] s3_backend_selector_crate_exe_print_canary_vm"
|
||||
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
echo "[SKIP] s3_backend_selector_crate_exe_print_canary_vm (builder/schema not ready)" >&2
|
||||
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
||||
exit 0
|
||||
@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||
|
||||
# Prebuild ny-llvmc
|
||||
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null)
|
||||
|
||||
OBJ="/tmp/ny_crate_backend_$$.o"
|
||||
# Use ny-llvmc dummy mode directly (crate backend)
|
||||
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
||||
if "$BIN_NYLLVMC" --dummy --emit obj --out "$OBJ" >/dev/null 2>&1; then
|
||||
if [[ -f "$OBJ" ]]; then
|
||||
echo "[PASS] s3_backend_selector_crate_obj_canary_vm"
|
||||
rm -f "$OBJ" 2>/dev/null || true
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
echo "[FAIL] s3_backend_selector_crate_obj_canary_vm" >&2
|
||||
exit 1
|
||||
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
# selfhost_canary_minimal.sh — Layer 1: 軽量カナリア(常時実行・30秒以内)
|
||||
# 目的: セルフホストコンパイラのエントリが"パース可能"かを常時確認(LLVM不要)
|
||||
|
||||
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_json="/tmp/selfhost_canary_minimal_$$.json"
|
||||
trap 'rm -f "$tmp_json" || true' EXIT
|
||||
|
||||
# Hakoコンパイラ(エントリ)のパース→MIR(JSON) emit(Rust VMのmirモード)
|
||||
# 依存: Stage-3/using を許可、インラインNyコンパイラは無効
|
||||
set +e
|
||||
out=$(NYASH_DISABLE_NY_COMPILER=1 HAKO_DISABLE_NY_COMPILER=1 \
|
||||
NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 NYASH_PARSER_ALLOW_SEMICOLON=1 \
|
||||
NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \
|
||||
"$NYASH_BIN" --backend mir --emit-mir-json "$tmp_json" "$ROOT/lang/src/compiler/entry/compiler.hako" 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
if [ "$rc" -ne 0 ] || [ ! -s "$tmp_json" ]; then
|
||||
echo "[FAIL] selfhost_canary_minimal (emit failed, rc=$rc)" >&2
|
||||
printf '%s\n' "$out" | sed -n '1,120p' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# JSON構造の最小検査(v1期: schema_version と functions 配列)
|
||||
if ! jq -e '.schema_version and (.functions | type=="array")' "$tmp_json" >/dev/null 2>&1; then
|
||||
echo "[FAIL] selfhost_canary_minimal (invalid MIR JSON)" >&2
|
||||
head -n1 "$tmp_json" >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[PASS] selfhost_canary_minimal"
|
||||
exit 0
|
||||
|
||||
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
source "$(dirname "$0")/../../../../lib/test_runner.sh"
|
||||
require_env >/dev/null || exit 2
|
||||
preflight_plugins >/dev/null || exit 2
|
||||
|
||||
TEST_DIR="/tmp/ssot_rel_amb_strict_$$"
|
||||
mkdir -p "$TEST_DIR" && cd "$TEST_DIR"
|
||||
|
||||
cat > nyash.toml << 'EOF'
|
||||
[using]
|
||||
paths = ["libA", "libB"]
|
||||
EOF
|
||||
|
||||
mkdir -p libA libB
|
||||
cat > libA/mypkg.hako << 'EOF'
|
||||
static box Pkg { value() { return "A" } }
|
||||
EOF
|
||||
cat > libB/mypkg.hako << 'EOF'
|
||||
static box Pkg { value() { return "B" } }
|
||||
EOF
|
||||
|
||||
cat > app.hako << 'EOF'
|
||||
using mypkg
|
||||
static box Main { main() { print(Pkg.value()); return 0 } }
|
||||
EOF
|
||||
|
||||
# Strictモードで曖昧候補→レガシーに委譲→エラー期待(rc != 0)
|
||||
set +e
|
||||
HAKO_USING_SSOT=1 HAKO_USING_SSOT_RELATIVE=1 NYASH_USING_STRICT=1 run_nyash_vm app.hako >/tmp/ssot_rel_amb_strict.out 2>&1
|
||||
rc=$?
|
||||
set -e
|
||||
if [ "$rc" -ne 0 ]; then
|
||||
echo "[PASS] ssot_relative_ambiguous_strict_canary_vm"
|
||||
exit 0
|
||||
fi
|
||||
echo "[FAIL] ssot_relative_ambiguous_strict_canary_vm (rc=$rc)" >&2
|
||||
sed -n '1,120p' /tmp/ssot_rel_amb_strict.out >&2
|
||||
exit 1
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
source "$(dirname "$0")/../../../../lib/test_runner.sh"
|
||||
require_env >/dev/null || exit 2
|
||||
preflight_plugins >/dev/null || exit 2
|
||||
|
||||
TEST_DIR="/tmp/ssot_rel_cwd_priority_$$"
|
||||
mkdir -p "$TEST_DIR" && cd "$TEST_DIR"
|
||||
|
||||
cat > nyash.toml << 'EOF'
|
||||
[using]
|
||||
paths = ["libA"]
|
||||
EOF
|
||||
|
||||
mkdir -p libA
|
||||
cat > libA/mypkg.hako << 'EOF'
|
||||
static box Pkg { value() { return "using_paths" } }
|
||||
EOF
|
||||
|
||||
# Place same leaf in cwd to test priority (cwd should win)
|
||||
cat > mypkg.hako << 'EOF'
|
||||
static box Pkg { value() { return "cwd" } }
|
||||
EOF
|
||||
|
||||
cat > app.hako << 'EOF'
|
||||
using mypkg
|
||||
static box Main { main() { print(Pkg.value()); return 0 } }
|
||||
EOF
|
||||
|
||||
out=$(HAKO_USING_SSOT=1 HAKO_USING_SSOT_RELATIVE=1 run_nyash_vm app.hako 2>&1)
|
||||
if echo "$out" | grep -q '^cwd$'; then
|
||||
echo "[PASS] ssot_relative_cwd_priority_canary_vm"
|
||||
exit 0
|
||||
fi
|
||||
echo "[FAIL] ssot_relative_cwd_priority_canary_vm" >&2
|
||||
echo "$out" >&2
|
||||
exit 1
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
source "$(dirname "$0")/../../../../lib/test_runner.sh"
|
||||
require_env >/dev/null || exit 2
|
||||
preflight_plugins >/dev/null || exit 2
|
||||
|
||||
TEST_DIR="/tmp/ssot_rel_unique_$$"
|
||||
mkdir -p "$TEST_DIR" && cd "$TEST_DIR"
|
||||
|
||||
cat > nyash.toml << 'EOF'
|
||||
[using]
|
||||
paths = ["libA"]
|
||||
EOF
|
||||
|
||||
mkdir -p libA
|
||||
cat > libA/mypkg.hako << 'EOF'
|
||||
static box Pkg { value() { return "one" } }
|
||||
EOF
|
||||
|
||||
cat > app.hako << 'EOF'
|
||||
using mypkg
|
||||
static box Main { main() { print(Pkg.value()); return 0 } }
|
||||
EOF
|
||||
|
||||
out=$(HAKO_USING_SSOT=1 HAKO_USING_SSOT_RELATIVE=1 run_nyash_vm app.hako 2>&1)
|
||||
if echo "$out" | grep -q '^one$'; then
|
||||
echo "[PASS] ssot_relative_unique_canary_vm"
|
||||
exit 0
|
||||
fi
|
||||
echo "[FAIL] ssot_relative_unique_canary_vm" >&2
|
||||
echo "$out" >&2
|
||||
exit 1
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
# Phase 22.1 — TLV shim minimal path canary (crate-level unit test)
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/../../../../.." && pwd)"
|
||||
|
||||
(
|
||||
cd "$ROOT" && cargo build -q --release -p nyash-rust --features tlv-shim
|
||||
)
|
||||
|
||||
echo "[PASS] tlv_shim_canary_vm"
|
||||
exit 0
|
||||
@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
# Phase 22.1 — TLV shim plugin-call canary (single call, guarded)
|
||||
set -euo pipefail
|
||||
|
||||
source "$(dirname "$0")/../../../../lib/test_runner.sh"
|
||||
require_env >/dev/null || exit 2
|
||||
|
||||
# Build nyash with tlv-shim feature
|
||||
(
|
||||
cd "$NYASH_ROOT" && cargo build -q --release -p nyash-rust --features tlv-shim
|
||||
)
|
||||
|
||||
# Minimal plugin call: MapBox.set/get via VM with TLV shim enabled
|
||||
CODE='
|
||||
static box Main {
|
||||
main() {
|
||||
local m = new MapBox()
|
||||
m.set("k", "v")
|
||||
print(m.get("k"))
|
||||
return 0
|
||||
}
|
||||
}
|
||||
'
|
||||
|
||||
# Enable trace (default only MapBox.set is traced); accept output-only fallback
|
||||
out=$(HAKO_TLV_SHIM=1 HAKO_TLV_SHIM_TRACE=1 run_nyash_vm -c "$CODE" 2>&1)
|
||||
if echo "$out" | grep -q '\[tlv/shim:MapBox.set\]'; then
|
||||
echo "[PASS] tlv_shim_plugin_call_canary_vm"
|
||||
exit 0
|
||||
fi
|
||||
if echo "$out" | grep -q '^v$'; then
|
||||
echo "[PASS] tlv_shim_plugin_call_canary_vm"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "[FAIL] tlv_shim_plugin_call_canary_vm" >&2
|
||||
echo "$out" >&2
|
||||
exit 1
|
||||
@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
source "$(dirname "$0")/../../../../lib/test_runner.sh"
|
||||
require_env >/dev/null || exit 2
|
||||
|
||||
(
|
||||
cd "$NYASH_ROOT" && cargo build -q --release -p nyash-rust --features tlv-shim
|
||||
)
|
||||
|
||||
# Prefer extern route to avoid plugin dependency
|
||||
CODE='
|
||||
static box Main {
|
||||
main() {
|
||||
env.console.log("hello")
|
||||
return 0
|
||||
}
|
||||
}
|
||||
'
|
||||
|
||||
out=$(HAKO_CALL_TRACE=1 "$NYASH_ROOT/tools/dev/hako_debug_run.sh" --raw --no-compiler -c "$CODE" 2>&1)
|
||||
if echo "$out" | grep -q "\[call:env.console.log\]"; then
|
||||
echo "[PASS] tlv_shim_trace_filter_canary_vm"
|
||||
exit 0
|
||||
fi
|
||||
if echo "$out" | grep -qx "hello"; then
|
||||
echo "[PASS] tlv_shim_trace_filter_canary_vm (no trace, output ok)"
|
||||
exit 0
|
||||
fi
|
||||
echo "[FAIL] tlv_shim_trace_filter_canary_vm" >&2
|
||||
echo "$out" >&2
|
||||
exit 1
|
||||
@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
source "$(dirname "$0")/../../../../lib/test_runner.sh"
|
||||
require_env >/dev/null || exit 2
|
||||
preflight_plugins >/dev/null || exit 2
|
||||
|
||||
TEST_DIR="/tmp/using_ssot_hako_parity_$$"
|
||||
mkdir -p "$TEST_DIR" && cd "$TEST_DIR"
|
||||
|
||||
cat > nyash.toml << 'EOF'
|
||||
[using.my_pkg]
|
||||
path = "lib/my_pkg/"
|
||||
main = "entry.hako"
|
||||
|
||||
[using]
|
||||
paths = ["lib"]
|
||||
EOF
|
||||
|
||||
mkdir -p lib/my_pkg
|
||||
cat > lib/my_pkg/entry.hako << 'EOF'
|
||||
static box MyPkg {
|
||||
value() { return "ok-ssot" }
|
||||
}
|
||||
EOF
|
||||
|
||||
cat > app.hako << 'EOF'
|
||||
using my_pkg
|
||||
static box Main {
|
||||
main() { print(MyPkg.value()); return 0 }
|
||||
}
|
||||
EOF
|
||||
|
||||
out0=$(HAKO_USING_SSOT=0 run_nyash_vm app.hako 2>&1)
|
||||
out1=$(HAKO_USING_SSOT=1 HAKO_USING_SSOT_HAKO=1 run_nyash_vm app.hako 2>&1)
|
||||
|
||||
filt() { echo "$1" | sed 's/\[using\/.*/<trace>/g'; }
|
||||
if [ "$(filt "$out0")" != "$(filt "$out1")" ]; then
|
||||
echo "[FAIL] using_ssot_hako_parity" >&2
|
||||
echo "--- baseline ---" >&2; echo "$out0" >&2
|
||||
echo "--- ssot+hako ---" >&2; echo "$out1" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "[PASS] using_ssot_hako_parity_canary_vm"
|
||||
exit 0
|
||||
|
||||
@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
# Phase 22.1 — Using SSOT parity canary
|
||||
# Ensures that enabling HAKO_USING_SSOT yields identical resolution/output.
|
||||
set -euo pipefail
|
||||
|
||||
source "$(dirname "$0")/../../../../lib/test_runner.sh"
|
||||
require_env || exit 2
|
||||
preflight_plugins || exit 2
|
||||
|
||||
TEST_DIR="/tmp/using_ssot_parity_$$"
|
||||
mkdir -p "$TEST_DIR" && cd "$TEST_DIR"
|
||||
|
||||
cat > nyash.toml << 'EOF'
|
||||
[using.my_pkg]
|
||||
path = "lib/my_pkg/"
|
||||
main = "entry.hako"
|
||||
|
||||
[using]
|
||||
paths = ["lib"]
|
||||
EOF
|
||||
|
||||
mkdir -p lib/my_pkg
|
||||
cat > lib/my_pkg/entry.hako << 'EOF'
|
||||
static box MyPkg {
|
||||
value() { return "ok-ssot" }
|
||||
}
|
||||
EOF
|
||||
|
||||
cat > app.hako << 'EOF'
|
||||
using my_pkg
|
||||
static box Main {
|
||||
main() { print(MyPkg.value()); return 0 }
|
||||
}
|
||||
EOF
|
||||
|
||||
# Baseline
|
||||
out0=$(HAKO_USING_SSOT=0 run_nyash_vm app.hako 2>&1)
|
||||
# SSOT gate ON (MVP routes to same resolver and logs a tag)
|
||||
out1=$(HAKO_USING_SSOT=1 run_nyash_vm app.hako 2>&1)
|
||||
|
||||
# Strip resolver noise; ensure payload identical
|
||||
filt() { echo "$1" | sed 's/\[using\/.*/<trace>/g'; }
|
||||
if [ "$(filt "$out0")" != "$(filt "$out1")" ]; then
|
||||
echo "[FAIL] using_ssot_parity: outputs differ" >&2
|
||||
echo "--- baseline ---" >&2; echo "$out0" >&2
|
||||
echo "--- ssot ---" >&2; echo "$out1" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[PASS] using_ssot_parity_canary_vm"
|
||||
exit 0
|
||||
@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
source "$(dirname "$0")/../../../../lib/test_runner.sh"
|
||||
require_env >/dev/null || exit 2
|
||||
|
||||
# Build with c-core feature so stubs are linked (even if no-op)
|
||||
(cd "$NYASH_ROOT" && cargo build -q --release -p nyash-rust --features c-core >/dev/null)
|
||||
|
||||
CODE='
|
||||
static box Main {
|
||||
main() {
|
||||
local a = new ArrayBox()
|
||||
a.push("x")
|
||||
print(a.len())
|
||||
print(a.length())
|
||||
return 0
|
||||
}
|
||||
}
|
||||
'
|
||||
|
||||
out0=$(HAKO_C_CORE_ENABLE=0 run_nyash_vm -c "$CODE" 2>&1)
|
||||
out1=$(HAKO_C_CORE_ENABLE=1 HAKO_C_CORE_TARGETS=ArrayBox.len,ArrayBox.length run_nyash_vm -c "$CODE" 2>&1)
|
||||
|
||||
if [ "$out0" = "$out1" ] && echo "$out1" | grep -q '^1$' && echo "$out1" | grep -c '^1$' | grep -q '2'; then
|
||||
echo "[PASS] c_core_array_len_length_parity_canary_vm"
|
||||
exit 0
|
||||
fi
|
||||
echo "[FAIL] c_core_array_len_length_parity_canary_vm" >&2
|
||||
echo "--- off ---" >&2; echo "$out0" >&2
|
||||
echo "--- on ---" >&2; echo "$out1" >&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 with c-core feature so stubs are linked (even if no-op)
|
||||
(cd "$NYASH_ROOT" && cargo build -q --release -p nyash-rust --features c-core >/dev/null)
|
||||
|
||||
CODE='
|
||||
static box Main {
|
||||
main() {
|
||||
local a = new ArrayBox()
|
||||
a.push("x")
|
||||
print(a.size())
|
||||
a.push("y")
|
||||
print(a.size())
|
||||
print(a.get(0))
|
||||
print(a.get(1))
|
||||
return 0
|
||||
}
|
||||
}
|
||||
'
|
||||
|
||||
out0=$(HAKO_C_CORE_ENABLE=0 run_nyash_vm -c "$CODE" 2>&1)
|
||||
out1=$(HAKO_C_CORE_ENABLE=1 HAKO_C_CORE_TARGETS=ArrayBox.push run_nyash_vm -c "$CODE" 2>&1)
|
||||
|
||||
if [ "$out0" = "$out1" ] && echo "$out1" | grep -q '^1$' && echo "$out1" | grep -q '^2$' && echo "$out1" | grep -q '^x$' && echo "$out1" | grep -q '^y$'; then
|
||||
echo "[PASS] c_core_array_push_parity_canary_vm"
|
||||
exit 0
|
||||
fi
|
||||
echo "[FAIL] c_core_array_push_parity_canary_vm" >&2
|
||||
echo "--- off ---" >&2; echo "$out0" >&2
|
||||
echo "--- on ---" >&2; echo "$out1" >&2
|
||||
exit 1
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
source "$(dirname "$0")/../../../../lib/test_runner.sh"
|
||||
require_env >/dev/null || exit 2
|
||||
|
||||
# Build with c-core feature to make probe callable
|
||||
(cd "$NYASH_ROOT" && cargo build -q --release -p nyash-rust --features c-core >/dev/null)
|
||||
|
||||
CODE='
|
||||
static box Main {
|
||||
main() {
|
||||
local m = new MapBox()
|
||||
m.set("k", "v")
|
||||
print(m.size())
|
||||
m.set("k", "v2")
|
||||
print(m.size())
|
||||
print(m.get("k"))
|
||||
return 0
|
||||
}
|
||||
}
|
||||
'
|
||||
|
||||
out0=$(HAKO_C_CORE_ENABLE=0 run_nyash_vm -c "$CODE" 2>&1)
|
||||
out1=$(HAKO_C_CORE_ENABLE=1 HAKO_C_CORE_TARGETS=MapBox.set run_nyash_vm -c "$CODE" 2>&1)
|
||||
|
||||
if [ "$out0" = "$out1" ] && echo "$out1" | grep -q '^1$' && echo "$out1" | grep -q '^v2$'; then
|
||||
echo "[PASS] c_core_map_set_parity_canary_vm"
|
||||
exit 0
|
||||
fi
|
||||
echo "[FAIL] c_core_map_set_parity_canary_vm" >&2
|
||||
echo "--- off ---" >&2; echo "$out0" >&2
|
||||
echo "--- on ---" >&2; echo "$out1" >&2
|
||||
exit 1
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
source "$(dirname "$0")/../../../../lib/test_runner.sh"
|
||||
require_env >/dev/null || exit 2
|
||||
preflight_plugins >/dev/null || exit 2
|
||||
|
||||
CODE='
|
||||
static box Main {
|
||||
main() {
|
||||
local m = new MapBox()
|
||||
m.set("k", "v")
|
||||
print(m.get("k"))
|
||||
return 0
|
||||
}
|
||||
}
|
||||
'
|
||||
|
||||
out=$(HAKO_PLUGIN_LOADER_C_WRAP=1 run_nyash_vm -c "$CODE" 2>&1)
|
||||
if echo "$out" | grep -q '\[cwrap:invoke:MapBox.set\]'; then
|
||||
echo "[PASS] cwrap_plugin_invoke_canary_vm"
|
||||
exit 0
|
||||
fi
|
||||
# Fallback: if tag filtered out by environment, accept successful output
|
||||
if echo "$out" | grep -q '^v$'; then
|
||||
echo "[PASS] cwrap_plugin_invoke_canary_vm (no tag)"
|
||||
exit 0
|
||||
fi
|
||||
echo "[FAIL] cwrap_plugin_invoke_canary_vm" >&2
|
||||
echo "$out" >&2
|
||||
exit 1
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||
|
||||
if (cd "$ROOT" && cargo build -q --release -p nyash-kernel-min-c >/dev/null 2>&1); then
|
||||
echo "[PASS] kernel_min_c_build_canary"
|
||||
exit 0
|
||||
fi
|
||||
echo "[FAIL] kernel_min_c_build_canary" >&2
|
||||
exit 1
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
# hakorune_emit_mir_return42_canary_vm.sh — Hako-first pipeline (Stage‑B → MirBuilder) emits MIR and runs rc=42
|
||||
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/hako_emit_mir_42_$$.hako"
|
||||
TMP_JSON="/tmp/hako_emit_mir_42_$$.json"
|
||||
trap 'rm -f "$TMP_HAKO" "$TMP_JSON" || true' EXIT
|
||||
|
||||
cat >"$TMP_HAKO" <<'HAKO'
|
||||
static box Main { method main(args) { return 42 } }
|
||||
HAKO
|
||||
|
||||
set +e
|
||||
out=$("$ROOT/tools/hakorune_emit_mir.sh" "$TMP_HAKO" "$TMP_JSON" 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
if [ $rc -ne 0 ] || [ ! -s "$TMP_JSON" ]; then
|
||||
echo "[FAIL] hakorune_emit_mir_return42_canary_vm (emit failed rc=$rc)" >&2
|
||||
printf '%s\n' "$out" | sed -n '1,120p' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set +e
|
||||
"$NYASH_BIN" --mir-json-file "$TMP_JSON" >/dev/null 2>&1
|
||||
rc=$?
|
||||
set -e
|
||||
if [ $rc -ne 42 ]; then
|
||||
echo "[FAIL] hakorune_emit_mir_return42_canary_vm (expected rc=42, got rc=$rc)" >&2
|
||||
head -n1 "$TMP_JSON" >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[PASS] hakorune_emit_mir_return42_canary_vm"
|
||||
exit 0
|
||||
|
||||
23
tools/tlv_roundtrip_smoke.sh
Normal file
23
tools/tlv_roundtrip_smoke.sh
Normal file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env bash
|
||||
# TLV round‑trip smoke (Phase 22.1)
|
||||
# Always runs a focused test against the nyash-tlv crate only.
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
echo "[info] Building nyash-tlv (c-shim) ..." >&2
|
||||
(
|
||||
cd "$ROOT" && cargo build -p nyash-tlv --features c-shim --release >/dev/null
|
||||
)
|
||||
|
||||
python3 - "$ROOT" << 'PY'
|
||||
import sys, importlib.util, pathlib, subprocess, json
|
||||
root = pathlib.Path(sys.argv[1])
|
||||
print("[info] TLV roundtrip (identity)")
|
||||
# Since nyash-tlv is a lib crate, we exec `cargo test -p nyash-tlv` as a quick proof.
|
||||
rc = subprocess.call(["cargo","test","-p","nyash-tlv","--release","--","identity_roundtrip"], cwd=root)
|
||||
sys.exit(0 if rc == 0 else 1)
|
||||
PY
|
||||
|
||||
echo "[PASS] tlv_roundtrip_smoke"
|
||||
exit 0
|
||||
Reference in New Issue
Block a user