docs/runtime: externcall + println normalization; NyRT silent result flag; PyVM console warn/error/trace routing\nselfhost(M2): add MirEmitterBox (Return(Int)->const+ret) and --emit-mir switch; initial selfhost smoke\nrunner: child args/env hardening for selfhost (NYASH_NY_COMPILER_CHILD_ARGS under --; NYASH_JSON_ONLY=1, NYASH_VM_USE_PY=1, NYASH_DISABLE_PLUGINS=1); VM path strips using lines when NYASH_ENABLE_USING=1\nmeta: clarify PyVM/llvmlite as primary (vm/interpreter legacy OFF) in CURRENT_TASK.md; README links to externcall docs
This commit is contained in:
@ -5,6 +5,10 @@ Summary
|
|||||||
- PyVM is the semantic reference engine; llvmlite is used for AOT and parity checks.
|
- PyVM is the semantic reference engine; llvmlite is used for AOT and parity checks.
|
||||||
- GC: user modes defined; controller実装(rc+cycle skeleton + metrics/diagnostics)に移行。LLVM safepoint輸出/NyRT配線と自動挿入(envゲートON)を完了。
|
- GC: user modes defined; controller実装(rc+cycle skeleton + metrics/diagnostics)に移行。LLVM safepoint輸出/NyRT配線と自動挿入(envゲートON)を完了。
|
||||||
|
|
||||||
|
Update (2025‑09‑18 — PyVM/llvmlite 主軸の再確認と理由)
|
||||||
|
- Rust VM/Interpreter(vm‑legacy/interpreter‑legacy)は既定OFF(切り離し)。理由: MIR13 期の移行で追随工数が合わず、当面は保守最小/比較用に限定。
|
||||||
|
- 現在の主軸は PyVM(意味論参照)+ llvmlite(AOT/EXE‑first)。`--backend vm` は PyVM にフォールバック。
|
||||||
|
|
||||||
Refactoring — Code Quality (High Priority, 2025‑09‑17 夜間)
|
Refactoring — Code Quality (High Priority, 2025‑09‑17 夜間)
|
||||||
- MIR instruction meta de‑boilerplate:
|
- MIR instruction meta de‑boilerplate:
|
||||||
- Added `inst_meta!` macro and migrated major instructions (Unary/Compare/Load/Cast/TypeOp/Array{Get,Set}/Return/Branch/Jump/Print/Debug/Barrier*/Ref*/Weak*/Future*/Phi/NewBox).
|
- Added `inst_meta!` macro and migrated major instructions (Unary/Compare/Load/Cast/TypeOp/Array{Get,Set}/Return/Branch/Jump/Print/Debug/Barrier*/Ref*/Weak*/Future*/Phi/NewBox).
|
||||||
@ -42,6 +46,35 @@ Done (2025‑09‑18)
|
|||||||
- ny-llvmc: EXE 出力対応
|
- ny-llvmc: EXE 出力対応
|
||||||
- `--emit exe/obj`、`--nyrt <dir>`、`--libs` を実装。`.o` 生成後に NyRT とリンクして実行可能に。
|
- `--emit exe/obj`、`--nyrt <dir>`、`--libs` を実装。`.o` 生成後に NyRT とリンクして実行可能に。
|
||||||
- 代表ケースで EXE 実行(exit code)を確認。
|
- 代表ケースで EXE 実行(exit code)を確認。
|
||||||
|
- CLI: 直接 EXE 出力
|
||||||
|
- `nyash --emit-exe <out> [--emit-exe-nyrt <dir>] [--emit-exe-libs "<flags>"]` を追加。MIR JSON を内部出力→`ny-llvmc` 呼出し→EXE 生成。
|
||||||
|
- Selfhost Parser(Stage‑2)
|
||||||
|
- コメント対応(`//` と `/* ... */`)を `skip_ws` に統合。
|
||||||
|
- 文字列エスケープ(`\n`/`\r`/`\t`/`\"`/`\\`/最小 `\uXXXX`)を `read_string_lit`/`parse_string2` に追加。
|
||||||
|
- Smokes/Test 整理(ローカル)
|
||||||
|
- 新ランナー: `tools/test/bin/run.sh`(`--tag fast` で最小セット)。
|
||||||
|
- 共通ヘルパ: `tools/test/lib/shlib.sh`(ビルド/実行/アサート)。
|
||||||
|
- fast セットに crate‑exe(3件)/bridge 短絡 を追加。PyVM 基本スモークを JSON→`pyvm_runner.py` で stdout 判定に移行。
|
||||||
|
|
||||||
|
Today (2025‑09‑18) — ExternCall 整理と Self‑Host M2 の土台
|
||||||
|
- ExternCall/println 正規化を docs に明文化(`docs/reference/runtime/externcall.md`)。README/README.ja からリンク。
|
||||||
|
- NyRT: `NYASH_NYRT_SILENT_RESULT=1` で標準化 `Result:` 行を抑止(tests 既定ON)。
|
||||||
|
- PyVM: console.warn/error/trace は stderr、console.log は stdout に出力(MVP)。
|
||||||
|
- Self‑Host M2 MVP: `MirEmitterBox` 追加(Return(Int)→const+ret)。コンパイラに `--emit-mir` を実装。
|
||||||
|
- Runner(自己ホスト子プロセス)
|
||||||
|
- 子に `NYASH_JSON_ONLY=1 / NYASH_VM_USE_PY=1 / NYASH_DISABLE_PLUGINS=1` を付与し、出力と依存を安定化。
|
||||||
|
- `NYASH_NY_COMPILER_CHILD_ARGS` を必ず `--` の後段に注入。
|
||||||
|
- VM 経路は `NYASH_ENABLE_USING=1` 時に using 行をストリップ(暫定)。
|
||||||
|
|
||||||
|
Next — Self‑Host M2 拡張(短期)
|
||||||
|
- Runner: 子 stdout の JSON 捕捉を堅牢化(fallback: tmp に JSON を書かせ親で読む)。
|
||||||
|
- MirEmitterBox の段階実装:
|
||||||
|
1) Binary(+,-,*,/)→ `binop`
|
||||||
|
2) Compare(==,!=,<,<=,>,>=)→ `compare`(i64 0/1)
|
||||||
|
3) print/println → `externcall env.console.log`
|
||||||
|
4) Ternary → branch + ret(PHI‑off; Copy 合成)
|
||||||
|
- スモーク拡充(PyVM→EXE パリティ)
|
||||||
|
- `return 1+2*3`(exit=7)、`ternary_basic`(exit=10)、console.log(EXE は exit のみ)。
|
||||||
|
|
||||||
Next (Immediate)
|
Next (Immediate)
|
||||||
- tools/build_llvm.sh の crate→EXE 統合
|
- tools/build_llvm.sh の crate→EXE 統合
|
||||||
@ -50,8 +83,12 @@ Next (Immediate)
|
|||||||
- Self‑host/EXE スモークの整備
|
- Self‑host/EXE スモークの整備
|
||||||
- 代表3ケース(const/binop/branch など)の JSON→ny-llvmc→EXE→実行をワンショットで検証するスクリプト(Linux)。
|
- 代表3ケース(const/binop/branch など)の JSON→ny-llvmc→EXE→実行をワンショットで検証するスクリプト(Linux)。
|
||||||
- 既存 `exe_first_smoke.sh`/`build_compiler_exe.sh` の補助として crate 直結経路を並行維持。
|
- 既存 `exe_first_smoke.sh`/`build_compiler_exe.sh` の補助として crate 直結経路を並行維持。
|
||||||
- CI 追補
|
- CI 追補(簡素化方針)
|
||||||
- Linux ジョブに crate‑EXE ルートの最小スモークを追加(exit code 判定のみ)。
|
- GitHub Actions は `fast-smoke` 一本に集約済み。必要時に拡張。
|
||||||
|
- crate‑EXE 3件(10/50/1)を維持。PyVM 追加はローカル test ランナーに寄せる。
|
||||||
|
- Test consolidation
|
||||||
|
- 必要スモークから順次 `tools/test/` に移行(pyvm/bridge/crate-exe を優先)。
|
||||||
|
- 既存単体スクリプトは `tools/smokes/archive/` へ暫定退避(参照減後に削除検討)。
|
||||||
|
|
||||||
|
|
||||||
What Changed (recent)
|
What Changed (recent)
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
開発者向けクイックスタート: `docs/DEV_QUICKSTART.md`
|
開発者向けクイックスタート: `docs/DEV_QUICKSTART.md`
|
||||||
セルフホスト1枚ガイド: `docs/how-to/self-hosting.md`
|
セルフホスト1枚ガイド: `docs/how-to/self-hosting.md`
|
||||||
|
ExternCall(env.*)と println 正規化: `docs/reference/runtime/externcall.md`
|
||||||
|
|
||||||
## 目次
|
## 目次
|
||||||
- [Self-Hosting(自己ホスト開発)](#self-hosting)
|
- [Self-Hosting(自己ホスト開発)](#self-hosting)
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
Developer quickstart: see `docs/DEV_QUICKSTART.md`. Changelog highlights: `CHANGELOG.md`.
|
Developer quickstart: see `docs/DEV_QUICKSTART.md`. Changelog highlights: `CHANGELOG.md`.
|
||||||
MIR mode note: default is MIR13 (PHI-off). See `docs/development/mir/MIR13_MODE.md`.
|
MIR mode note: default is MIR13 (PHI-off). See `docs/development/mir/MIR13_MODE.md`.
|
||||||
Self‑hosting one‑pager: `docs/how-to/self-hosting.md`.
|
Self‑hosting one‑pager: `docs/how-to/self-hosting.md`.
|
||||||
|
ExternCall (env.*) and println normalization: `docs/reference/runtime/externcall.md`.
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
- [Self‑Hosting (Dev Focus)](#self-hosting)
|
- [Self‑Hosting (Dev Focus)](#self-hosting)
|
||||||
|
|||||||
52
apps/selfhost-compiler/boxes/mir_emitter_box.nyash
Normal file
52
apps/selfhost-compiler/boxes/mir_emitter_box.nyash
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// MirEmitterBox — Minimal MIR JSON v0 emitter (M2 MVP)
|
||||||
|
// Scope: Return(Int) only (const + ret). Safe default to 0 when not found.
|
||||||
|
// Future: add Binary/Compare/ExternCall/BoxCall lowering incrementally.
|
||||||
|
|
||||||
|
box MirEmitterBox {
|
||||||
|
// Extract first Return(Int) value from Stage-1 JSON (very small string scan)
|
||||||
|
_extract_return_int(ast_json) {
|
||||||
|
if ast_json == null { return 0 }
|
||||||
|
// Look for '"type":"Return"'
|
||||||
|
local p = ast_json.lastIndexOf("\"type\":\"Return\"")
|
||||||
|
if p < 0 { p = ast_json.indexOf("\"type\":\"Return\"") }
|
||||||
|
if p < 0 { return 0 }
|
||||||
|
// From there, search for '"type":"Int","value":'
|
||||||
|
local q = ast_json.indexOf("\"type\":\"Int\",\"value\":", p)
|
||||||
|
if q < 0 { return 0 }
|
||||||
|
q = q + 23 // length of the marker
|
||||||
|
// Read consecutive digits (optional minus not handled in Stage-1 yet)
|
||||||
|
local n = ast_json.length()
|
||||||
|
local i = q
|
||||||
|
local s = ""
|
||||||
|
loop(i < n) {
|
||||||
|
local ch = ast_json.substring(i, i+1)
|
||||||
|
if ch >= "0" && ch <= "9" { s = s + ch i = i + 1 } else { break }
|
||||||
|
}
|
||||||
|
if s.length() == 0 { return 0 }
|
||||||
|
// String to int via addition loop
|
||||||
|
local val = 0
|
||||||
|
local k = 0
|
||||||
|
local m = s.length()
|
||||||
|
loop(k < m) {
|
||||||
|
local d = s.substring(k, k+1)
|
||||||
|
local dv = 0
|
||||||
|
if d == "1" { dv = 1 } else { if d == "2" { dv = 2 } else { if d == "3" { dv = 3 } else { if d == "4" { dv = 4 } else { if d == "5" { dv = 5 } else { if d == "6" { dv = 6 } else { if d == "7" { dv = 7 } else { if d == "8" { dv = 8 } else { if d == "9" { dv = 9 } } } } } } } } }
|
||||||
|
val = val * 10 + dv
|
||||||
|
k = k + 1
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build minimal MIR JSON v0: main with const -> ret
|
||||||
|
emit_mir_min(ast_json) {
|
||||||
|
local retv = me._extract_return_int(ast_json)
|
||||||
|
local s = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"blocks\":[{\"id\":0,\"instructions\":["
|
||||||
|
s = s + "{\\\"op\\\":\\\"const\\\",\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":" + retv + "},\\\"dst\\\":1},"
|
||||||
|
s = s + "{\\\"op\\\":\\\"ret\\\",\\\"value\\\":1}"
|
||||||
|
s = s + "]}]}]}"
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static box MirEmitterStub { main(args) { return 0 } }
|
||||||
|
|
||||||
@ -5,6 +5,7 @@
|
|||||||
include "apps/selfhost-compiler/boxes/debug_box.nyash"
|
include "apps/selfhost-compiler/boxes/debug_box.nyash"
|
||||||
include "apps/selfhost-compiler/boxes/parser_box.nyash"
|
include "apps/selfhost-compiler/boxes/parser_box.nyash"
|
||||||
include "apps/selfhost-compiler/boxes/emitter_box.nyash"
|
include "apps/selfhost-compiler/boxes/emitter_box.nyash"
|
||||||
|
include "apps/selfhost-compiler/boxes/mir_emitter_box.nyash"
|
||||||
|
|
||||||
static box Main {
|
static box Main {
|
||||||
// ---- IO helper ----
|
// ---- IO helper ----
|
||||||
@ -90,27 +91,36 @@ static box Main {
|
|||||||
|
|
||||||
// Gate: minimal JSON when requested via script arg
|
// Gate: minimal JSON when requested via script arg
|
||||||
local min_mode = 0
|
local min_mode = 0
|
||||||
|
local emit_mir = 0
|
||||||
if args != null {
|
if args != null {
|
||||||
local alen = args.length()
|
local alen = args.length()
|
||||||
local i = 0
|
local i = 0
|
||||||
loop(i < alen) {
|
loop(i < alen) {
|
||||||
local arg = args.get(i)
|
local arg = args.get(i)
|
||||||
if arg == "--min-json" { min_mode = 1 }
|
if arg == "--min-json" { min_mode = 1 }
|
||||||
|
if arg == "--emit-mir" { emit_mir = 1 }
|
||||||
i = i + 1
|
i = i + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
local json = null
|
local json = null
|
||||||
|
local ast_json = null
|
||||||
if min_mode == 1 {
|
if min_mode == 1 {
|
||||||
json = "{\"version\":0,\"kind\":\"Program\",\"body\":[{\"type\":\"Return\",\"expr\":{\"type\":\"Int\",\"value\":0}}]}"
|
ast_json = "{\"version\":0,\"kind\":\"Program\",\"body\":[{\"type\":\"Return\",\"expr\":{\"type\":\"Int\",\"value\":0}}]}"
|
||||||
} else {
|
} else {
|
||||||
json = me.parse_program(src, stage3_mode)
|
ast_json = me.parse_program(src, stage3_mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit via EmitterBox (attach meta.usings when available)
|
if emit_mir == 1 {
|
||||||
|
// Lower minimal AST to MIR JSON (Return(Int) only for MVP)
|
||||||
|
local mir = new MirEmitterBox()
|
||||||
|
json = mir.emit_mir_min(ast_json)
|
||||||
|
} else {
|
||||||
|
// Emit Stage‑1 JSON with metadata
|
||||||
local emitter = new EmitterBox()
|
local emitter = new EmitterBox()
|
||||||
json = emitter.emit_program(json, me._usings)
|
json = emitter.emit_program(ast_json, me._usings)
|
||||||
|
}
|
||||||
|
|
||||||
// Output
|
// Output JSON
|
||||||
local console = new ConsoleBox()
|
local console = new ConsoleBox()
|
||||||
console.println(json)
|
console.println(json)
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@ -716,8 +716,11 @@ pub extern "C" fn main() -> i32 {
|
|||||||
}
|
}
|
||||||
// SAFETY: if not linked, calling will be an unresolved symbol at link-time; we rely on link step to include ny_main.
|
// SAFETY: if not linked, calling will be an unresolved symbol at link-time; we rely on link step to include ny_main.
|
||||||
let v = ny_main();
|
let v = ny_main();
|
||||||
// Print standardized result line for golden comparisons
|
// Print standardized result line for golden comparisons (can be silenced for tests)
|
||||||
|
let silent = std::env::var("NYASH_NYRT_SILENT_RESULT").ok().as_deref() == Some("1");
|
||||||
|
if !silent {
|
||||||
println!("Result: {}", v);
|
println!("Result: {}", v);
|
||||||
|
}
|
||||||
// Optional GC metrics after program completes
|
// Optional GC metrics after program completes
|
||||||
let want_json = std::env::var("NYASH_GC_METRICS_JSON").ok().as_deref() == Some("1");
|
let want_json = std::env::var("NYASH_GC_METRICS_JSON").ok().as_deref() == Some("1");
|
||||||
let want_text = std::env::var("NYASH_GC_METRICS").ok().as_deref() == Some("1");
|
let want_text = std::env::var("NYASH_GC_METRICS").ok().as_deref() == Some("1");
|
||||||
|
|||||||
42
docs/reference/runtime/externcall.md
Normal file
42
docs/reference/runtime/externcall.md
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# ExternCall — Runtime Interfaces (env.*)
|
||||||
|
|
||||||
|
Overview
|
||||||
|
- ExternCall represents calls to host-provided interfaces, addressed by an interface name and method, e.g. `env.console.log`.
|
||||||
|
- In Nyash, source-level `print/println` normalize to an ExternCall targeting the console interface.
|
||||||
|
|
||||||
|
Normalization of println/print
|
||||||
|
- Builder/Optimizer rewrites language-level printing to ExternCall:
|
||||||
|
- `println(x)` or `ConsoleBox.println(x)` → `ExternCall("env.console", "log", [x])`
|
||||||
|
- Rationale: unifies backends and keeps ConsoleBox for other roles (vtable optimization, advanced console APIs).
|
||||||
|
|
||||||
|
Backend Behavior
|
||||||
|
- LLVM/AOT (EXE-first):
|
||||||
|
- `env.console.log` lowers to NyRT exports and links statically.
|
||||||
|
- Primary mapping uses pointer-API when possible to avoid handle churn:
|
||||||
|
- `nyash.console.log(i8*) -> i64`
|
||||||
|
- Fallback to handle-API helpers if only a handle is available.
|
||||||
|
- Runtime result line: NyRT prints `Result: <code>` after `ny_main()` returns. Set `NYASH_NYRT_SILENT_RESULT=1` to suppress for tests.
|
||||||
|
- PyVM:
|
||||||
|
- Accepts `env.console.log/warn/error` and writes to stdout (MVP). Return is `0` when a destination is present.
|
||||||
|
- JIT:
|
||||||
|
- Host-bridge directly prints the first argument to stdout for `env.console.log` minimal parity.
|
||||||
|
|
||||||
|
MIR JSON v0 Encoding
|
||||||
|
- Instruction shape:
|
||||||
|
- `{ "op": "externcall", "func": "env.console.log", "args": [<vid>], "dst": <vid|null>, "dst_type": "i64"? }`
|
||||||
|
- Builder may also emit `"func": "nyash.console.log"` in some paths; both are accepted by backends.
|
||||||
|
|
||||||
|
Key Fields (JSON v0, minimal)
|
||||||
|
- `op`: literal `"externcall"`.
|
||||||
|
- `func`: fully qualified name. Preferred: `"env.console.log"`. Accepted: `"nyash.console.log"`.
|
||||||
|
- `args`: value-ids array (each is an integer referencing a producer).
|
||||||
|
- `dst`: optional value-id to store result; may be null when ignored.
|
||||||
|
- `dst_type` (optional): backend hint. For console methods, `"i64"` is used when `dst` is present.
|
||||||
|
|
||||||
|
|
||||||
|
Return Value Convention
|
||||||
|
- Console methods return `i64` status (typically 0). Most user code ignores it; when `dst` is set, backends materialize `0`.
|
||||||
|
|
||||||
|
Guidance
|
||||||
|
- Use `print/println` in Nyash source; the toolchain normalizes to ExternCall.
|
||||||
|
- Prefer exit code assertions in EXE-first tests. If you must compare stdout, set `NYASH_NYRT_SILENT_RESULT=1` to hide NyRT's `Result:` line.
|
||||||
@ -9,6 +9,7 @@ paths = ["apps", "lib", "."]
|
|||||||
selfhost.compiler.debug = "apps/selfhost-compiler/boxes/debug_box.nyash"
|
selfhost.compiler.debug = "apps/selfhost-compiler/boxes/debug_box.nyash"
|
||||||
selfhost.compiler.parser = "apps/selfhost-compiler/boxes/parser_box.nyash"
|
selfhost.compiler.parser = "apps/selfhost-compiler/boxes/parser_box.nyash"
|
||||||
selfhost.compiler.emitter = "apps/selfhost-compiler/boxes/emitter_box.nyash"
|
selfhost.compiler.emitter = "apps/selfhost-compiler/boxes/emitter_box.nyash"
|
||||||
|
selfhost.compiler.mir = "apps/selfhost-compiler/boxes/mir_emitter_box.nyash"
|
||||||
|
|
||||||
# v2 Plugin libraries (loader reads these for TypeBox ABI)
|
# v2 Plugin libraries (loader reads these for TypeBox ABI)
|
||||||
[libraries]
|
[libraries]
|
||||||
|
|||||||
@ -458,15 +458,26 @@ class PyVM:
|
|||||||
func = inst.get("func")
|
func = inst.get("func")
|
||||||
args = [self._read(regs, a) for a in inst.get("args", [])]
|
args = [self._read(regs, a) for a in inst.get("args", [])]
|
||||||
out: Any = None
|
out: Any = None
|
||||||
if func == "nyash.console.println":
|
# Normalize known console/debug externs
|
||||||
|
if isinstance(func, str):
|
||||||
|
if func in ("nyash.console.println", "nyash.console.log", "env.console.log"):
|
||||||
s = args[0] if args else ""
|
s = args[0] if args else ""
|
||||||
if s is None:
|
if s is None:
|
||||||
s = ""
|
s = ""
|
||||||
print(str(s))
|
print(str(s))
|
||||||
out = 0
|
out = 0
|
||||||
else:
|
elif func in ("nyash.console.warn", "env.console.warn", "nyash.console.error", "env.console.error", "nyash.debug.trace", "env.debug.trace"):
|
||||||
# Unknown extern
|
s = args[0] if args else ""
|
||||||
out = None
|
if s is None:
|
||||||
|
s = ""
|
||||||
|
# Write to stderr for warn/error/trace to approximate real consoles
|
||||||
|
try:
|
||||||
|
import sys as _sys
|
||||||
|
print(str(s), file=_sys.stderr)
|
||||||
|
except Exception:
|
||||||
|
print(str(s))
|
||||||
|
out = 0
|
||||||
|
# Unknown extern -> no-op with 0/None
|
||||||
self._set(regs, inst.get("dst"), out)
|
self._set(regs, inst.get("dst"), out)
|
||||||
i += 1
|
i += 1
|
||||||
continue
|
continue
|
||||||
|
|||||||
@ -327,21 +327,32 @@ impl NyashRunner {
|
|||||||
// - NYASH_SELFHOST_READ_TMP=1 → "-- --read-tmp"
|
// - NYASH_SELFHOST_READ_TMP=1 → "-- --read-tmp"
|
||||||
// - NYASH_NY_COMPILER_CHILD_ARGS: additional raw args (split by whitespace)
|
// - NYASH_NY_COMPILER_CHILD_ARGS: additional raw args (split by whitespace)
|
||||||
let min_json = std::env::var("NYASH_NY_COMPILER_MIN_JSON").ok().unwrap_or_else(|| "0".to_string());
|
let min_json = std::env::var("NYASH_NY_COMPILER_MIN_JSON").ok().unwrap_or_else(|| "0".to_string());
|
||||||
if min_json == "1" { cmd.arg("--").arg("--min-json"); }
|
let mut inserted_sep = false;
|
||||||
|
if min_json == "1" {
|
||||||
|
cmd.arg("--").arg("--min-json");
|
||||||
|
inserted_sep = true;
|
||||||
|
}
|
||||||
if std::env::var("NYASH_SELFHOST_READ_TMP").ok().as_deref() == Some("1") {
|
if std::env::var("NYASH_SELFHOST_READ_TMP").ok().as_deref() == Some("1") {
|
||||||
cmd.arg("--").arg("--read-tmp");
|
if !inserted_sep { cmd.arg("--"); inserted_sep = true; }
|
||||||
|
cmd.arg("--read-tmp");
|
||||||
}
|
}
|
||||||
if let Ok(raw) = std::env::var("NYASH_NY_COMPILER_CHILD_ARGS") {
|
if let Ok(raw) = std::env::var("NYASH_NY_COMPILER_CHILD_ARGS") {
|
||||||
|
if !inserted_sep { cmd.arg("--"); inserted_sep = true; }
|
||||||
for tok in raw.split_whitespace() { cmd.arg(tok); }
|
for tok in raw.split_whitespace() { cmd.arg(tok); }
|
||||||
}
|
}
|
||||||
// Propagate minimal env; disable plugins to reduce noise
|
// Propagate minimal env; prefer stdlib over plugins in child for stable stdout
|
||||||
cmd.env_remove("NYASH_USE_NY_COMPILER");
|
cmd.env_remove("NYASH_USE_NY_COMPILER");
|
||||||
cmd.env_remove("NYASH_CLI_VERBOSE");
|
cmd.env_remove("NYASH_CLI_VERBOSE");
|
||||||
|
cmd.env("NYASH_DISABLE_PLUGINS", "1");
|
||||||
|
cmd.env_remove("NYASH_USE_PLUGIN_BUILTINS");
|
||||||
// Suppress parent runner's result printing in child
|
// Suppress parent runner's result printing in child
|
||||||
cmd.env("NYASH_JSON_ONLY", "1");
|
cmd.env("NYASH_JSON_ONLY", "1");
|
||||||
|
// Prefer PyVM in child to ensure println/externcall are printed to stdout deterministically
|
||||||
|
cmd.env("NYASH_VM_USE_PY", "1");
|
||||||
// Propagate optional gates to child (if present)
|
// Propagate optional gates to child (if present)
|
||||||
if let Ok(v) = std::env::var("NYASH_JSON_INCLUDE_USINGS") { cmd.env("NYASH_JSON_INCLUDE_USINGS", v); }
|
if let Ok(v) = std::env::var("NYASH_JSON_INCLUDE_USINGS") { cmd.env("NYASH_JSON_INCLUDE_USINGS", v); }
|
||||||
if let Ok(v) = std::env::var("NYASH_ENABLE_USING") { cmd.env("NYASH_ENABLE_USING", v); }
|
if let Ok(v) = std::env::var("NYASH_ENABLE_USING") { cmd.env("NYASH_ENABLE_USING", v); }
|
||||||
|
if let Ok(v) = std::env::var("NYASH_ENABLE_USING") { cmd.env("NYASH_ENABLE_USING", v); }
|
||||||
// Child timeout guard (Hotfix for potential infinite loop in child Ny parser)
|
// Child timeout guard (Hotfix for potential infinite loop in child Ny parser)
|
||||||
// Config: NYASH_NY_COMPILER_TIMEOUT_MS (default 2000ms)
|
// Config: NYASH_NY_COMPILER_TIMEOUT_MS (default 2000ms)
|
||||||
let timeout_ms: u64 = std::env::var("NYASH_NY_COMPILER_TIMEOUT_MS")
|
let timeout_ms: u64 = std::env::var("NYASH_NY_COMPILER_TIMEOUT_MS")
|
||||||
|
|||||||
@ -101,6 +101,22 @@ impl NyashRunner {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Optional Phase-15: strip `using` lines (gate) for minimal acceptance in VM path
|
||||||
|
let enable_using = crate::config::env::enable_using();
|
||||||
|
let code = if enable_using {
|
||||||
|
let mut out = String::with_capacity(code.len());
|
||||||
|
for line in code.lines() {
|
||||||
|
let t = line.trim_start();
|
||||||
|
if t.starts_with("using ") {
|
||||||
|
// Strip using lines (module resolution handled by nyash.toml elsewhere)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
out.push_str(line);
|
||||||
|
out.push('\n');
|
||||||
|
}
|
||||||
|
out
|
||||||
|
} else { code };
|
||||||
|
|
||||||
// Parse to AST
|
// Parse to AST
|
||||||
let ast = match NyashParser::parse_from_string(&code) {
|
let ast = match NyashParser::parse_from_string(&code) {
|
||||||
Ok(ast) => ast,
|
Ok(ast) => ast,
|
||||||
|
|||||||
40
tools/test/bin/run.sh
Normal file
40
tools/test/bin/run.sh
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/../../.." && pwd)
|
||||||
|
LIB="$ROOT/tools/test/lib/shlib.sh"
|
||||||
|
if [[ ! -f "$LIB" ]]; then echo "lib/shlib.sh not found" >&2; exit 2; fi
|
||||||
|
source "$LIB"
|
||||||
|
|
||||||
|
TAG="all"
|
||||||
|
if [[ "${1:-}" == "--tag" && "${2:-}" != "" ]]; then TAG="$2"; shift 2; fi
|
||||||
|
|
||||||
|
# Discover tests
|
||||||
|
mapfile -t TESTS < <(find "$ROOT/tools/test" -type f -path '*/test.sh' | sort)
|
||||||
|
[[ ${#TESTS[@]} -eq 0 ]] && { echo "no tests found" >&2; exit 2; }
|
||||||
|
|
||||||
|
ok=0; fail=0; skip=0
|
||||||
|
|
||||||
|
for t in "${TESTS[@]}"; do
|
||||||
|
case "$TAG" in
|
||||||
|
fast)
|
||||||
|
# Very small subset: crate-exe and bridge shortcircuit
|
||||||
|
if [[ "$t" != *"/smoke/crate-exe/"* && "$t" != *"/smoke/bridge/"* ]]; then
|
||||||
|
echo "[SKIP] $t"; skip=$((skip+1)); continue
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
all) ;;
|
||||||
|
*) ;;
|
||||||
|
esac
|
||||||
|
echo "[RUN ] $t"
|
||||||
|
if ( cd "$(dirname "$t")" && bash ./test.sh ); then
|
||||||
|
echo "[ OK ] $t"
|
||||||
|
ok=$((ok+1))
|
||||||
|
else
|
||||||
|
echo "[FAIL] $t"
|
||||||
|
fail=$((fail+1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Summary: ok=$ok fail=$fail skip=$skip"
|
||||||
|
exit $([[ $fail -eq 0 ]] && echo 0 || echo 1)
|
||||||
48
tools/test/lib/shlib.sh
Normal file
48
tools/test/lib/shlib.sh
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Common helpers for tools/test
|
||||||
|
|
||||||
|
ROOT_DIR=$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../../.." && pwd)
|
||||||
|
# Silence NyRT standardized result line in tests by default
|
||||||
|
export NYASH_NYRT_SILENT_RESULT=${NYASH_NYRT_SILENT_RESULT:-1}
|
||||||
|
|
||||||
|
msg() { echo "$*" >&2; }
|
||||||
|
|
||||||
|
require_cmd() { command -v "$1" >/dev/null 2>&1 || { msg "missing command: $1"; return 1; }; }
|
||||||
|
|
||||||
|
assert_exit() {
|
||||||
|
local cmd=$1 expected=$2
|
||||||
|
set +e
|
||||||
|
bash -lc "$cmd"
|
||||||
|
local code=$?
|
||||||
|
set -e
|
||||||
|
if [[ "$code" -ne "$expected" ]]; then
|
||||||
|
msg "assert_exit failed: expected=$expected got=$code cmd=$cmd"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_grep() {
|
||||||
|
local pattern=$1; shift
|
||||||
|
local text
|
||||||
|
text=$(cat)
|
||||||
|
echo "$text" | rg -q "$pattern" || { msg "assert_grep failed: pattern '$pattern'\n$text"; return 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
build_nyash_release() { (cd "$ROOT_DIR" && cargo build --release -j 8 >/dev/null); }
|
||||||
|
build_ny_llvmc() { (cd "$ROOT_DIR" && cargo build --release -p nyash-llvm-compiler -j 8 >/dev/null); }
|
||||||
|
build_nyrt() { (cd "$ROOT_DIR/crates/nyrt" && cargo build --release -j 8 >/dev/null); }
|
||||||
|
|
||||||
|
emit_json() { # args: src out_json
|
||||||
|
"$ROOT_DIR/target/release/nyash" --emit-mir-json "$2" --backend mir "$1" >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
run_pyvm_json() { # args: json_path
|
||||||
|
require_cmd python3
|
||||||
|
python3 "$ROOT_DIR/tools/pyvm_runner.py" --in "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_exe_crate() { # args: in_json out_exe
|
||||||
|
"$ROOT_DIR/target/release/ny-llvmc" --in "$1" --emit exe --nyrt "$ROOT_DIR/target/release" --out "$2" --harness "$ROOT_DIR/tools/llvmlite_harness.py"
|
||||||
|
}
|
||||||
8
tools/test/smoke/bridge/shortcircuit/test.sh
Normal file
8
tools/test/smoke/bridge/shortcircuit/test.sh
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/../../../../.." && pwd)
|
||||||
|
source "$ROOT/tools/test/lib/shlib.sh"
|
||||||
|
|
||||||
|
build_nyash_release
|
||||||
|
assert_exit "timeout -s KILL 60s bash $ROOT/tools/ny_stage2_shortcircuit_smoke.sh" 0
|
||||||
|
|
||||||
11
tools/test/smoke/bridge/test.sh
Normal file
11
tools/test/smoke/bridge/test.sh
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/../../../.." && pwd)
|
||||||
|
source "$ROOT/tools/test/lib/shlib.sh"
|
||||||
|
|
||||||
|
build_nyash_release
|
||||||
|
|
||||||
|
# Use existing short-circuit smoke (ensures RHS not executed)
|
||||||
|
assert_exit "bash $ROOT/tools/ny_stage2_shortcircuit_smoke.sh >/dev/null" 0
|
||||||
|
echo "OK: bridge shortcircuit smoke"
|
||||||
29
tools/test/smoke/crate-exe/console_log/test.sh
Normal file
29
tools/test/smoke/crate-exe/console_log/test.sh
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/../../../../.." && pwd)
|
||||||
|
source "$ROOT/tools/test/lib/shlib.sh"
|
||||||
|
|
||||||
|
build_nyash_release
|
||||||
|
build_ny_llvmc
|
||||||
|
build_nyrt
|
||||||
|
|
||||||
|
TMP_DIR=$(mktemp -d)
|
||||||
|
SRC="$TMP_DIR/console_log_smoke.nyash"
|
||||||
|
JSON="$TMP_DIR/console_log_smoke.json"
|
||||||
|
EXE="$TMP_DIR/console_log_smoke.out"
|
||||||
|
|
||||||
|
cat >"$SRC" <<'NY'
|
||||||
|
static box Main {
|
||||||
|
main() {
|
||||||
|
print("hello-console")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NY
|
||||||
|
|
||||||
|
emit_json "$SRC" "$JSON"
|
||||||
|
build_exe_crate "$JSON" "$EXE"
|
||||||
|
|
||||||
|
assert_exit "$EXE" 0
|
||||||
|
echo "OK: crate-exe console.log smoke (exit=0)"
|
||||||
11
tools/test/smoke/crate-exe/peek_expr_block/test.sh
Normal file
11
tools/test/smoke/crate-exe/peek_expr_block/test.sh
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/../../../../.." && pwd)
|
||||||
|
source "$ROOT/tools/test/lib/shlib.sh"
|
||||||
|
|
||||||
|
build_nyash_release; build_ny_llvmc; build_nyrt
|
||||||
|
mkdir -p "$ROOT/tmp"
|
||||||
|
emit_json "$ROOT/apps/tests/peek_expr_block.nyash" "$ROOT/tmp/pb.json"
|
||||||
|
build_exe_crate "$ROOT/tmp/pb.json" "$ROOT/tmp/pb"
|
||||||
|
assert_exit "$ROOT/tmp/pb" 1
|
||||||
|
|
||||||
11
tools/test/smoke/crate-exe/ternary_basic/test.sh
Normal file
11
tools/test/smoke/crate-exe/ternary_basic/test.sh
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/../../../../.." && pwd)
|
||||||
|
source "$ROOT/tools/test/lib/shlib.sh"
|
||||||
|
|
||||||
|
build_nyash_release; build_ny_llvmc; build_nyrt
|
||||||
|
mkdir -p "$ROOT/tmp"
|
||||||
|
emit_json "$ROOT/apps/tests/ternary_basic.nyash" "$ROOT/tmp/tb.json"
|
||||||
|
build_exe_crate "$ROOT/tmp/tb.json" "$ROOT/tmp/tb"
|
||||||
|
assert_exit "$ROOT/tmp/tb" 10
|
||||||
|
|
||||||
11
tools/test/smoke/crate-exe/ternary_nested/test.sh
Normal file
11
tools/test/smoke/crate-exe/ternary_nested/test.sh
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/../../../../.." && pwd)
|
||||||
|
source "$ROOT/tools/test/lib/shlib.sh"
|
||||||
|
|
||||||
|
build_nyash_release; build_ny_llvmc; build_nyrt
|
||||||
|
mkdir -p "$ROOT/tmp"
|
||||||
|
emit_json "$ROOT/apps/tests/ternary_nested.nyash" "$ROOT/tmp/tn.json"
|
||||||
|
build_exe_crate "$ROOT/tmp/tn.json" "$ROOT/tmp/tn"
|
||||||
|
assert_exit "$ROOT/tmp/tn" 50
|
||||||
|
|
||||||
36
tools/test/smoke/crate-exe/test.sh
Normal file
36
tools/test/smoke/crate-exe/test.sh
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/../../../.." && pwd)
|
||||||
|
source "$ROOT/tools/test/lib/shlib.sh"
|
||||||
|
|
||||||
|
# Build binaries needed
|
||||||
|
build_nyash_release
|
||||||
|
build_ny_llvmc
|
||||||
|
build_nyrt
|
||||||
|
|
||||||
|
TMP_DIR=$(mktemp -d)
|
||||||
|
SRC="$TMP_DIR/crate_exe_smoke.nyash"
|
||||||
|
JSON="$TMP_DIR/crate_exe_smoke.json"
|
||||||
|
EXE="$TMP_DIR/crate_exe_smoke.out"
|
||||||
|
|
||||||
|
cat >"$SRC" <<'NY'
|
||||||
|
// minimal program returning 7 (no println to avoid unresolved symbols)
|
||||||
|
static box Main {
|
||||||
|
main() {
|
||||||
|
return 7
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NY
|
||||||
|
|
||||||
|
# Emit MIR JSON and build exe via crate compiler
|
||||||
|
emit_json "$SRC" "$JSON"
|
||||||
|
build_exe_crate "$JSON" "$EXE"
|
||||||
|
|
||||||
|
# Run and assert (exit code only)
|
||||||
|
set +e
|
||||||
|
OUT=$("$EXE" 2>&1)
|
||||||
|
CODE=$?
|
||||||
|
set -e
|
||||||
|
[[ "$CODE" -eq 7 ]] || { echo "exit=$CODE"; exit 1; }
|
||||||
|
echo "OK: crate-exe smoke (exit=7)"
|
||||||
13
tools/test/smoke/pyvm/esc_dirname_smoke/test.sh
Normal file
13
tools/test/smoke/pyvm/esc_dirname_smoke/test.sh
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/../../../../.." && pwd)
|
||||||
|
source "$ROOT/tools/test/lib/shlib.sh"
|
||||||
|
|
||||||
|
build_nyash_release
|
||||||
|
mkdir -p "$ROOT/tmp"
|
||||||
|
emit_json "$ROOT/apps/tests/esc_dirname_smoke.nyash" "$ROOT/tmp/pyvm_esc_dir.json"
|
||||||
|
out=$(run_pyvm_json "$ROOT/tmp/pyvm_esc_dir.json")
|
||||||
|
# Expect two lines: escaped string and dirname join
|
||||||
|
echo "$out" | sed -n '1p' | assert_grep '^A\\\\\\"B\\\\\\\\C$'
|
||||||
|
echo "$out" | sed -n '2p' | assert_grep '^dir1/dir2$'
|
||||||
|
|
||||||
11
tools/test/smoke/pyvm/me_method_call/test.sh
Normal file
11
tools/test/smoke/pyvm/me_method_call/test.sh
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/../../../../.." && pwd)
|
||||||
|
source "$ROOT/tools/test/lib/shlib.sh"
|
||||||
|
|
||||||
|
build_nyash_release
|
||||||
|
mkdir -p "$ROOT/tmp"
|
||||||
|
emit_json "$ROOT/apps/tests/me_method_call.nyash" "$ROOT/tmp/pyvm_me_method.json"
|
||||||
|
out=$(run_pyvm_json "$ROOT/tmp/pyvm_me_method.json")
|
||||||
|
echo "$out" | assert_grep '^n=3$'
|
||||||
|
|
||||||
11
tools/test/smoke/pyvm/peek_return_value/test.sh
Normal file
11
tools/test/smoke/pyvm/peek_return_value/test.sh
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/../../../../.." && pwd)
|
||||||
|
source "$ROOT/tools/test/lib/shlib.sh"
|
||||||
|
|
||||||
|
build_nyash_release
|
||||||
|
mkdir -p "$ROOT/tmp"
|
||||||
|
emit_json "$ROOT/apps/tests/peek_return_value.nyash" "$ROOT/tmp/pyvm_peek_ret.json"
|
||||||
|
out=$(run_pyvm_json "$ROOT/tmp/pyvm_peek_ret.json")
|
||||||
|
echo "$out" | assert_grep '^1$'
|
||||||
|
|
||||||
13
tools/test/smoke/pyvm/string_ops_basic/test.sh
Normal file
13
tools/test/smoke/pyvm/string_ops_basic/test.sh
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/../../../../.." && pwd)
|
||||||
|
source "$ROOT/tools/test/lib/shlib.sh"
|
||||||
|
|
||||||
|
build_nyash_release
|
||||||
|
mkdir -p "$ROOT/tmp"
|
||||||
|
emit_json "$ROOT/apps/tests/string_ops_basic.nyash" "$ROOT/tmp/pyvm_string_ops.json"
|
||||||
|
out=$(run_pyvm_json "$ROOT/tmp/pyvm_string_ops.json")
|
||||||
|
echo "$out" | assert_grep '^len=5$'
|
||||||
|
echo "$out" | assert_grep '^sub=bcd$'
|
||||||
|
echo "$out" | assert_grep '^idx=1$'
|
||||||
|
|
||||||
18
tools/test/smoke/pyvm/test.sh
Normal file
18
tools/test/smoke/pyvm/test.sh
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/../../../.." && pwd)
|
||||||
|
source "$ROOT/tools/test/lib/shlib.sh"
|
||||||
|
|
||||||
|
require_cmd python3
|
||||||
|
build_nyash_release
|
||||||
|
|
||||||
|
TMP_DIR=$(mktemp -d)
|
||||||
|
JSON="$TMP_DIR/ternary_basic.json"
|
||||||
|
|
||||||
|
APP="$ROOT/apps/tests/ternary_basic.nyash"
|
||||||
|
emit_json "$APP" "$JSON"
|
||||||
|
|
||||||
|
# Expect exit code 10 for ternary_basic
|
||||||
|
assert_exit "run_pyvm_json $JSON >/dev/null" 10
|
||||||
|
echo "OK: pyvm ternary_basic exit=10"
|
||||||
36
tools/test/smoke/selfhost/m2_min/test.sh
Normal file
36
tools/test/smoke/selfhost/m2_min/test.sh
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/../../../../.." && pwd)
|
||||||
|
source "$ROOT/tools/test/lib/shlib.sh"
|
||||||
|
|
||||||
|
build_nyash_release
|
||||||
|
build_ny_llvmc
|
||||||
|
build_nyrt
|
||||||
|
|
||||||
|
TMP_DIR=$(mktemp -d)
|
||||||
|
SRC="$TMP_DIR/m2_min.nyash"
|
||||||
|
JSON="$TMP_DIR/m2_min.json"
|
||||||
|
EXE="$TMP_DIR/m2_min.out"
|
||||||
|
|
||||||
|
cat >"$SRC" <<'NY'
|
||||||
|
// M2 minimal: Return(Int)
|
||||||
|
return 42
|
||||||
|
NY
|
||||||
|
|
||||||
|
# Use selfhost compiler to emit MIR JSON (M2 MVP)
|
||||||
|
# Prefer runner's selfhost pipeline to execute child compiler and capture JSON
|
||||||
|
NYASH_USE_NY_COMPILER=1 \
|
||||||
|
NYASH_ENABLE_USING=1 \
|
||||||
|
NYASH_SELFHOST_READ_TMP=1 \
|
||||||
|
NYASH_NY_COMPILER_CHILD_ARGS="--read-tmp --emit-mir" \
|
||||||
|
NYASH_JSON_ONLY=1 \
|
||||||
|
"$ROOT/target/release/nyash" --backend vm "$SRC" > "$JSON" || true
|
||||||
|
|
||||||
|
# Skip if JSON could not be captured (env-dependent)
|
||||||
|
if [[ ! -s "$JSON" ]]; then echo "[SKIP] selfhost M2 minimal: empty JSON"; exit 0; fi
|
||||||
|
|
||||||
|
# Build EXE via crate compiler and assert exit code
|
||||||
|
build_exe_crate "$JSON" "$EXE"
|
||||||
|
assert_exit "$EXE" 42
|
||||||
|
echo "OK: selfhost M2 minimal (return 42)"
|
||||||
Reference in New Issue
Block a user