2025-09-16 00:01:31 +09:00
/*!
* Runner selfhost helpers — Ny compiler pipeline ( Ny -> JSON v0 )
*
* Transitional shim : provides a stable entrypoint from callers , while the
* heavy implementation currently lives in modes / common . rs . Next step will
* migrate the full implementation here .
* /
use super ::* ;
2025-09-19 22:27:59 +09:00
use nyash_rust ::{ mir ::MirCompiler , parser ::NyashParser } ;
2025-09-17 07:43:07 +09:00
use std ::{ fs , process } ;
2025-09-16 00:01:31 +09:00
impl NyashRunner {
/// Selfhost (Ny -> JSON v0) pipeline: EXE/VM/Python フォールバック含む
pub ( crate ) fn try_run_selfhost_pipeline ( & self , filename : & str ) -> bool {
use std ::io ::Write ;
2025-11-17 00:48:18 +09:00
// Phase 25.1b: guard selfhost pipeline to Ny-only sources.
// `.hako` / other extensionsは Stage‑ B / JSON v0 bridge 側の責務なので、
// ここでは Ny/Nyash 拡張子以外は即座にスキップする。
let path = std ::path ::Path ::new ( filename ) ;
if let Some ( ext ) = path . extension ( ) . and_then ( | s | s . to_str ( ) ) {
match ext {
" ny " | " nyash " = > { /* continue */ }
_ = > {
crate ::cli_v! (
" [ny-compiler] skip selfhost pipeline for non-Ny source: {} (ext={}) " ,
filename ,
ext
) ;
return false ;
}
}
} else {
// No extension: treat as non-Ny for safety
crate ::cli_v! (
" [ny-compiler] skip selfhost pipeline for source without extension: {} " ,
filename
) ;
return false ;
}
2025-09-16 00:01:31 +09:00
// Read input source
let code = match fs ::read_to_string ( filename ) {
Ok ( c ) = > c ,
2025-09-17 07:43:07 +09:00
Err ( e ) = > {
eprintln! ( " [ny-compiler] read error: {} " , e ) ;
return false ;
}
2025-09-16 00:01:31 +09:00
} ;
2025-11-04 09:25:36 +09:00
// Optional Phase-15: using prelude merge (text-based for speed)
2025-09-16 00:01:31 +09:00
let mut code_ref : std ::borrow ::Cow < '_ , str > = std ::borrow ::Cow ::Borrowed ( & code ) ;
2025-09-19 02:07:38 +09:00
if crate ::config ::env ::enable_using ( ) {
2025-11-04 09:25:36 +09:00
let using_ast = crate ::config ::env ::using_ast_enabled ( ) ;
if using_ast {
// Text-based merge: faster for inline/selfhost execution
match crate ::runner ::modes ::common_util ::resolve ::merge_prelude_text ( self , & code , filename ) {
Ok ( merged ) = > {
code_ref = std ::borrow ::Cow ::Owned ( merged ) ;
}
Err ( e ) = > {
eprintln! ( " [ny-compiler] using text merge error: {} " , e ) ;
2025-09-26 00:27:02 +09:00
return false ;
}
}
2025-11-04 09:25:36 +09:00
} else {
// Legacy: strip only (no prelude merge)
match crate ::runner ::modes ::common_util ::resolve ::resolve_prelude_paths_profiled ( self , & code , filename ) {
Ok ( ( clean , paths ) ) = > {
if ! paths . is_empty ( ) {
eprintln! ( " [ny-compiler] using: AST prelude merge is disabled in this profile. Enable NYASH_USING_AST=1 or remove 'using' lines. " ) ;
return false ;
}
code_ref = std ::borrow ::Cow ::Owned ( clean ) ;
}
Err ( e ) = > { eprintln! ( " [ny-compiler] {} " , e ) ; return false ; }
}
2025-09-16 00:01:31 +09:00
}
}
2025-09-28 02:05:41 +09:00
// Promote dev sugar to standard: pre-expand line-head '@name[:T] = expr' to 'local name[:T] = expr'
{
let expanded = crate ::runner ::modes ::common_util ::resolve ::preexpand_at_local ( code_ref . as_ref ( ) ) ;
code_ref = std ::borrow ::Cow ::Owned ( expanded ) ;
}
2025-09-16 00:01:31 +09:00
// Write to tmp/ny_parser_input.ny (as expected by Ny parser v0), unless forced to reuse existing tmp
2025-09-17 06:55:39 +09:00
let use_tmp_only = crate ::config ::env ::ny_compiler_use_tmp_only ( ) ;
2025-09-16 00:01:31 +09:00
let tmp_dir = std ::path ::Path ::new ( " tmp " ) ;
if let Err ( e ) = std ::fs ::create_dir_all ( tmp_dir ) {
eprintln! ( " [ny-compiler] mkdir tmp failed: {} " , e ) ;
return false ;
}
2025-09-19 22:27:59 +09:00
// Optional macro pre‑ expand path for selfhost
// Default: auto when macro engine is enabled (safe: PyVM only)
// Gate: NYASH_MACRO_SELFHOST_PRE_EXPAND={1|auto|0}
{
let preenv = std ::env ::var ( " NYASH_MACRO_SELFHOST_PRE_EXPAND " )
. ok ( )
. or_else ( | | if crate ::r#macro ::enabled ( ) { Some ( " auto " . to_string ( ) ) } else { None } ) ;
let do_pre = match preenv . as_deref ( ) {
Some ( " 1 " ) = > true ,
Some ( " auto " ) = > crate ::r#macro ::enabled ( ) & & crate ::config ::env ::vm_use_py ( ) ,
_ = > false ,
} ;
if do_pre & & crate ::r#macro ::enabled ( ) {
crate ::cli_v! ( " [ny-compiler] selfhost macro pre-expand: engaging (mode={:?}) " , preenv ) ;
match NyashParser ::parse_from_string ( code_ref . as_ref ( ) ) {
Ok ( ast0 ) = > {
let ast = crate ::r#macro ::maybe_expand_and_dump ( & ast0 , false ) ;
// Compile to MIR and execute (respect VM/PyVM policy similar to vm mode)
let mut mir_compiler = MirCompiler ::with_options ( true ) ;
match mir_compiler . compile ( ast ) {
Ok ( result ) = > {
let prefer_pyvm = crate ::config ::env ::vm_use_py ( ) ;
if prefer_pyvm {
if let Ok ( code ) = crate ::runner ::modes ::common_util ::pyvm ::run_pyvm_harness_lib ( & result . module , " selfhost-preexpand " ) {
println! ( " Result: {} " , code ) ;
std ::process ::exit ( code ) ;
} else {
eprintln! ( " ❌ PyVM error (selfhost-preexpand) " ) ;
std ::process ::exit ( 1 ) ;
}
} else {
// For now, only PyVM path is supported in pre-expand mode; fall back otherwise.
crate ::cli_v! ( " [ny-compiler] pre-expand path requires NYASH_VM_USE_PY=1; falling back to default selfhost " ) ;
return false ;
}
}
Err ( e ) = > {
eprintln! ( " [ny-compiler] pre-expand compile error: {} " , e ) ;
return false ;
}
}
}
Err ( e ) = > {
eprintln! ( " [ny-compiler] pre-expand parse error: {} " , e ) ;
return false ;
}
}
}
}
2025-09-16 00:01:31 +09:00
let tmp_path = tmp_dir . join ( " ny_parser_input.ny " ) ;
if ! use_tmp_only {
match std ::fs ::File ::create ( & tmp_path ) {
Ok ( mut f ) = > {
if let Err ( e ) = f . write_all ( code_ref . as_bytes ( ) ) {
eprintln! ( " [ny-compiler] write tmp failed: {} " , e ) ;
return false ;
}
}
2025-09-17 07:43:07 +09:00
Err ( e ) = > {
eprintln! ( " [ny-compiler] open tmp failed: {} " , e ) ;
return false ;
}
2025-09-16 00:01:31 +09:00
}
}
2025-11-06 15:41:52 +09:00
// Preferred: run Ny selfhost compiler program (apps/selfhost/compiler/compiler.hako)
2025-09-17 01:55:08 +09:00
// This avoids inline embedding pitfalls and supports Stage-3 gating via args.
{
2025-09-18 13:35:38 +09:00
use crate ::runner ::modes ::common_util ::selfhost ::{ child , json } ;
2025-09-17 07:43:07 +09:00
let exe = std ::env ::current_exe ( )
. unwrap_or_else ( | _ | std ::path ::PathBuf ::from ( " target/release/nyash " ) ) ;
2025-11-06 15:41:52 +09:00
let parser_prog = std ::path ::Path ::new ( " apps/selfhost/compiler/compiler.hako " ) ;
2025-09-17 01:55:08 +09:00
if parser_prog . exists ( ) {
2025-09-18 13:35:38 +09:00
// Build extra args forwarded to child program
2025-09-22 21:52:39 +09:00
let mut extra_owned : Vec < String > = Vec ::new ( ) ;
2025-09-17 06:55:39 +09:00
if crate ::config ::env ::ny_compiler_min_json ( ) {
2025-09-22 21:52:39 +09:00
extra_owned . push ( " -- " . to_string ( ) ) ;
extra_owned . push ( " --min-json " . to_string ( ) ) ;
2025-09-17 01:55:08 +09:00
}
2025-09-22 21:52:39 +09:00
extra_owned . push ( " -- " . to_string ( ) ) ;
extra_owned . push ( " --read-tmp " . to_string ( ) ) ;
2025-09-17 06:55:39 +09:00
if crate ::config ::env ::ny_compiler_stage3 ( ) {
2025-09-22 21:52:39 +09:00
extra_owned . push ( " -- " . to_string ( ) ) ;
extra_owned . push ( " --stage3 " . to_string ( ) ) ;
2025-09-17 01:55:08 +09:00
}
2025-09-22 21:52:39 +09:00
// Optional: map env toggles to child args (prepasses)
if std ::env ::var ( " NYASH_SCOPEBOX_ENABLE " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
extra_owned . push ( " -- " . to_string ( ) ) ;
extra_owned . push ( " --scopebox " . to_string ( ) ) ;
}
if std ::env ::var ( " NYASH_LOOPFORM_NORMALIZE " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
extra_owned . push ( " -- " . to_string ( ) ) ;
extra_owned . push ( " --loopform " . to_string ( ) ) ;
}
// Optional: developer-provided child args passthrough (space-separated)
if let Ok ( raw ) = std ::env ::var ( " NYASH_SELFHOST_CHILD_ARGS " ) {
let items : Vec < String > = raw
. split ( ' ' )
. filter ( | s | ! s . trim ( ) . is_empty ( ) )
. map ( | s | s . to_string ( ) )
. collect ( ) ;
if ! items . is_empty ( ) {
extra_owned . push ( " -- " . to_string ( ) ) ;
for it in items { extra_owned . push ( it ) ; }
}
}
let extra : Vec < & str > = extra_owned . iter ( ) . map ( | s | s . as_str ( ) ) . collect ( ) ;
2025-09-17 06:55:39 +09:00
let timeout_ms : u64 = crate ::config ::env ::ny_compiler_timeout_ms ( ) ;
2025-09-18 13:35:38 +09:00
if let Some ( line ) = child ::run_ny_program_capture_json (
& exe ,
parser_prog ,
timeout_ms ,
& extra ,
2025-11-02 04:13:17 +09:00
& [
" NYASH_USE_NY_COMPILER " ,
" NYASH_CLI_VERBOSE " ,
] ,
& [
( " NYASH_JSON_ONLY " , " 1 " ) ,
( " NYASH_DISABLE_PLUGINS " , " 1 " ) ,
( " NYASH_SKIP_TOML_ENV " , " 1 " ) ,
( " NYASH_USING_AST " , " 0 " ) ,
( " NYASH_ALLOW_USING_FILE " , " 0 " ) ,
( " HAKO_ALLOW_USING_FILE " , " 0 " ) ,
] ,
2025-09-18 13:35:38 +09:00
) {
match json ::parse_json_v0_line ( & line ) {
Ok ( module ) = > {
2025-11-02 15:43:43 +09:00
if crate ::config ::env ::cli_verbose ( ) {
if crate ::config ::env ::cli_verbose ( ) {
super ::json_v0_bridge ::maybe_dump_mir ( & module ) ;
}
}
2025-09-18 13:35:38 +09:00
let emit_only = crate ::config ::env ::ny_compiler_emit_only ( ) ;
if emit_only {
return false ;
2025-09-17 01:55:08 +09:00
}
2025-09-18 13:35:38 +09:00
// Prefer PyVM path when requested
if crate ::config ::env ::vm_use_py ( ) {
if let Some ( code ) = crate ::runner ::modes ::common_util ::selfhost ::json ::run_pyvm_module ( & module , " selfhost " ) {
println! ( " Result: {} " , code ) ;
std ::process ::exit ( code ) ;
2025-09-17 01:55:08 +09:00
}
}
self . execute_mir_module ( & module ) ;
return true ;
}
2025-09-18 13:35:38 +09:00
Err ( e ) = > {
eprintln! ( " [ny-compiler] json parse error (child): {} " , e ) ;
2025-09-17 01:55:08 +09:00
}
}
}
}
}
2025-11-17 00:48:18 +09:00
// Python MVP (optional): lightweight harness to produce JSON v0.
// Phase 25.1b: default OFF( NYASH_NY_COMPILER_USE_PY=1 のときだけ有効)。
if std ::env ::var ( " NYASH_NY_COMPILER_USE_PY " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
2025-09-17 07:43:07 +09:00
if let Ok ( py3 ) = which ::which ( " python3 " ) {
let py = std ::path ::Path ::new ( " tools/ny_parser_mvp.py " ) ;
if py . exists ( ) {
let mut cmd = std ::process ::Command ::new ( & py3 ) ;
2025-11-17 00:48:18 +09:00
// Phase 25.1b: Use selfhost compiler env for consistency
crate ::runner ::child_env ::apply_selfhost_compiler_env ( & mut cmd ) ;
2025-09-17 07:43:07 +09:00
cmd . arg ( py ) . arg ( & tmp_path ) ;
2025-09-17 20:33:19 +09:00
let timeout_ms : u64 = std ::env ::var ( " NYASH_NY_COMPILER_TIMEOUT_MS " )
. ok ( )
. and_then ( | s | s . parse ( ) . ok ( ) )
2025-11-17 00:48:18 +09:00
. unwrap_or ( 60000 ) ; // Phase 25.1b: Increased to 60000ms (60s) for consistency
2025-09-17 20:33:19 +09:00
let out = match super ::modes ::common_util ::io ::spawn_with_timeout ( cmd , timeout_ms ) {
2025-09-17 07:43:07 +09:00
Ok ( o ) = > o ,
2025-09-17 20:33:19 +09:00
Err ( e ) = > { eprintln! ( " [ny-compiler] python harness failed: {} " , e ) ; return false ; }
2025-09-17 07:43:07 +09:00
} ;
2025-09-17 20:33:19 +09:00
if ! out . timed_out {
2025-09-18 13:35:38 +09:00
if let Ok ( s ) = String ::from_utf8 ( out . stdout ) {
if let Some ( line ) = crate ::runner ::modes ::common_util ::selfhost ::json ::first_json_v0_line ( & s ) {
2025-09-17 07:43:07 +09:00
match super ::json_v0_bridge ::parse_json_v0_to_module ( & line ) {
Ok ( module ) = > {
2025-11-02 15:43:43 +09:00
if crate ::config ::env ::cli_verbose ( ) {
if crate ::config ::env ::cli_verbose ( ) {
super ::json_v0_bridge ::maybe_dump_mir ( & module ) ;
}
}
2025-09-17 07:43:07 +09:00
let emit_only =
std ::env ::var ( " NYASH_NY_COMPILER_EMIT_ONLY " )
. unwrap_or_else ( | _ | " 1 " . to_string ( ) )
= = " 1 " ;
if emit_only {
return false ;
}
// Prefer PyVM for selfhost pipeline (parity reference)
2025-09-19 02:07:38 +09:00
if std ::env ::var ( " NYASH_VM_USE_PY " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
let code = match crate ::runner ::modes ::common_util ::pyvm ::run_pyvm_harness ( & module , " selfhost-py " ) {
Ok ( c ) = > c ,
Err ( e ) = > { eprintln! ( " ❌ PyVM error: {} " , e ) ; 1 }
} ;
2025-09-17 07:43:07 +09:00
println! ( " Result: {} " , code ) ;
std ::process ::exit ( code ) ;
2025-09-16 14:57:05 +09:00
}
2025-11-01 19:57:09 +09:00
crate ::runner ::child_env ::pre_run_reset_oob_if_strict ( ) ;
2025-09-17 07:43:07 +09:00
self . execute_mir_module ( & module ) ;
2025-11-01 19:57:09 +09:00
if crate ::config ::env ::oob_strict_fail ( ) & & crate ::runtime ::observe ::oob_seen ( ) {
eprintln! ( " [selfhost][oob-strict] Out-of-bounds observed → exit(1) " ) ;
std ::process ::exit ( 1 ) ;
}
2025-09-17 07:43:07 +09:00
return true ;
}
Err ( e ) = > {
eprintln! ( " [ny-compiler] json parse error: {} " , e ) ;
return false ;
2025-09-16 14:57:05 +09:00
}
}
}
}
}
}
}
2025-09-17 07:43:07 +09:00
}
2025-09-16 00:01:31 +09:00
// EXE-first: if requested, try external parser EXE (nyash_compiler)
if std ::env ::var ( " NYASH_USE_NY_COMPILER_EXE " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
// Resolve parser EXE path
let exe_path = if let Ok ( p ) = std ::env ::var ( " NYASH_NY_COMPILER_EXE_PATH " ) {
std ::path ::PathBuf ::from ( p )
} else {
let mut p = std ::path ::PathBuf ::from ( " dist/nyash_compiler " ) ;
#[ cfg(windows) ]
2025-09-17 07:43:07 +09:00
{
p . push ( " nyash_compiler.exe " ) ;
}
2025-09-16 00:01:31 +09:00
#[ cfg(not(windows)) ]
2025-09-17 07:43:07 +09:00
{
p . push ( " nyash_compiler " ) ;
}
2025-09-16 00:01:31 +09:00
if ! p . exists ( ) {
// Try PATH
2025-09-17 07:43:07 +09:00
if let Ok ( w ) = which ::which ( " nyash_compiler " ) {
w
} else {
p
}
} else {
p
}
2025-09-16 00:01:31 +09:00
} ;
if exe_path . exists ( ) {
2025-09-17 07:43:07 +09:00
let timeout_ms : u64 = std ::env ::var ( " NYASH_NY_COMPILER_TIMEOUT_MS " )
. ok ( )
. and_then ( | s | s . parse ( ) . ok ( ) )
. unwrap_or ( 2000 ) ;
2025-09-17 20:33:19 +09:00
if let Some ( module ) = super ::modes ::common_util ::selfhost_exe ::exe_try_parse_json_v0 ( filename , timeout_ms ) {
2025-11-02 15:43:43 +09:00
if crate ::config ::env ::cli_verbose ( ) {
super ::json_v0_bridge ::maybe_dump_mir ( & module ) ;
}
2025-09-17 20:33:19 +09:00
let emit_only = std ::env ::var ( " NYASH_NY_COMPILER_EMIT_ONLY " )
. unwrap_or_else ( | _ | " 1 " . to_string ( ) )
= = " 1 " ;
if emit_only { return false ; }
// Prefer PyVM when requested (reference semantics)
if std ::env ::var ( " NYASH_VM_USE_PY " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
if let Ok ( py3 ) = which ::which ( " python3 " ) {
let runner = std ::path ::Path ::new ( " tools/pyvm_runner.py " ) ;
if runner . exists ( ) {
let tmp_dir = std ::path ::Path ::new ( " tmp " ) ;
let _ = std ::fs ::create_dir_all ( tmp_dir ) ;
let mir_json_path = tmp_dir . join ( " nyash_pyvm_mir.json " ) ;
if let Err ( e ) = crate ::runner ::mir_json_emit ::emit_mir_json_for_harness_bin ( & module , & mir_json_path ) {
eprintln! ( " ❌ PyVM MIR JSON emit error: {} " , e ) ;
process ::exit ( 1 ) ;
}
2025-09-19 02:07:38 +09:00
crate ::cli_v! ( " [Bridge] using PyVM (selfhost) → {} " , mir_json_path . display ( ) ) ;
2025-09-21 08:53:00 +09:00
let allow_top = crate ::config ::env ::entry_allow_toplevel_main ( ) ;
2025-09-17 20:33:19 +09:00
let entry = if module . functions . contains_key ( " Main.main " ) { " Main.main " }
2025-09-21 08:53:00 +09:00
else if allow_top & & module . functions . contains_key ( " main " ) { " main " }
else if module . functions . contains_key ( " main " ) { eprintln! ( " [entry] Warning: using top-level 'main' without explicit allow; set NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 to silence. " ) ; " main " }
else { " Main.main " } ;
2025-11-02 07:26:26 +09:00
let mut cmd = std ::process ::Command ::new ( py3 ) ;
crate ::runner ::child_env ::apply_core_wrapper_env ( & mut cmd ) ;
let status = cmd
2025-09-17 20:33:19 +09:00
. args ( [ " tools/pyvm_runner.py " , " --in " , & mir_json_path . display ( ) . to_string ( ) , " --entry " , entry ] )
. status ( )
. map_err ( | e | format! ( " spawn pyvm: {} " , e ) )
. unwrap ( ) ;
let code = status . code ( ) . unwrap_or ( 1 ) ;
println! ( " Result: {} " , code ) ;
std ::process ::exit ( code ) ;
2025-09-16 00:01:31 +09:00
}
}
}
2025-11-01 19:57:09 +09:00
crate ::runner ::child_env ::pre_run_reset_oob_if_strict ( ) ;
2025-11-01 20:06:41 +09:00
crate ::runner ::child_env ::pre_run_reset_oob_if_strict ( ) ;
2025-09-17 20:33:19 +09:00
self . execute_mir_module ( & module ) ;
2025-11-01 19:57:09 +09:00
if crate ::config ::env ::oob_strict_fail ( ) & & crate ::runtime ::observe ::oob_seen ( ) {
eprintln! ( " [selfhost][oob-strict] Out-of-bounds observed → exit(1) " ) ;
std ::process ::exit ( 1 ) ;
}
2025-11-01 20:06:41 +09:00
if crate ::config ::env ::oob_strict_fail ( ) & & crate ::runtime ::observe ::oob_seen ( ) {
eprintln! ( " [selfhost][oob-strict] Out-of-bounds observed → exit(1) " ) ;
std ::process ::exit ( 1 ) ;
}
2025-09-17 20:33:19 +09:00
return true ;
} else {
return false ;
2025-09-16 00:01:31 +09:00
}
}
}
2025-09-16 14:57:05 +09:00
// Fallback: inline VM run (embed source into a tiny wrapper that prints JSON)
2025-11-17 00:48:18 +09:00
// Phase 25.1b: この経路は Ny selfhost 実験用だったが、現在は不安定かつ .hako 側 selfhost builder の
// デバッグを阻害するため、既定で無効化する。Ny selfhost が必要な場合は別の .sh ベースの
// パイプライン( tools/ny_selfhost_inline.sh など)を使う想定とし、ここでは常に Rust 既定
// パスへフォールバックする。
crate ::cli_v! ( " [ny-compiler] inline selfhost pipeline disabled (Phase 25.1b); falling back to default path " ) ;
2025-11-18 18:56:35 +09:00
// Dev-only escape hatch: allow forcing the old inline path when explicitly requested.
if std ::env ::var ( " NYASH_SELFHOST_INLINE_FORCE " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
match super ::json_v0_bridge ::parse_json_v0_to_module ( " " ) {
Ok ( module ) = > {
2025-11-02 15:43:43 +09:00
if crate ::config ::env ::cli_verbose ( ) {
2025-11-18 18:56:35 +09:00
if crate ::config ::env ::cli_verbose ( ) {
super ::json_v0_bridge ::maybe_dump_mir ( & module ) ;
}
}
let emit_only = std ::env ::var ( " NYASH_NY_COMPILER_EMIT_ONLY " )
. unwrap_or_else ( | _ | " 1 " . to_string ( ) )
= = " 1 " ;
if emit_only {
return false ;
2025-11-02 15:43:43 +09:00
}
2025-09-16 14:57:05 +09:00
// Phase-15 policy: when NYASH_VM_USE_PY=1, prefer PyVM as reference executor
// regardless of BoxCall presence to ensure semantics parity (e.g., PHI merges).
let prefer_pyvm = std ::env ::var ( " NYASH_VM_USE_PY " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) ;
// Backward compatibility: if not preferring PyVM explicitly, still auto-enable when BoxCalls exist.
2025-09-17 07:43:07 +09:00
let needs_pyvm = ! prefer_pyvm
& & module . functions . values ( ) . any ( | f | {
f . blocks . values ( ) . any ( | bb | {
bb . instructions . iter ( ) . any ( | inst | {
matches! ( inst , crate ::mir ::MirInstruction ::BoxCall { .. } )
} )
} )
} ) ;
2025-11-18 18:56:35 +09:00
if prefer_pyvm | | needs_pyvm {
let label = if prefer_pyvm { " selfhost " } else { " selfhost-fallback " } ;
if let Some ( code ) = crate ::runner ::modes ::common_util ::selfhost ::json ::run_pyvm_module ( & module , label ) {
println! ( " Result: {} " , code ) ;
std ::process ::exit ( code ) ;
}
2025-09-16 00:01:31 +09:00
}
2025-11-18 18:56:35 +09:00
crate ::runner ::child_env ::pre_run_reset_oob_if_strict ( ) ;
self . execute_mir_module ( & module ) ;
if crate ::config ::env ::oob_strict_fail ( ) & & crate ::runtime ::observe ::oob_seen ( ) {
eprintln! ( " [selfhost][oob-strict] Out-of-bounds observed → exit(1) " ) ;
std ::process ::exit ( 1 ) ;
}
return true ;
2025-09-16 00:01:31 +09:00
}
2025-11-18 18:56:35 +09:00
Err ( e ) = > {
eprintln! ( " ❌ JSON v0 bridge error: {} " , e ) ;
return false ;
2025-11-01 20:06:41 +09:00
}
2025-09-17 07:43:07 +09:00
}
2025-09-16 00:01:31 +09:00
}
2025-11-18 18:56:35 +09:00
// Default path: always fall back to existing Rust runner.
return false ;
2025-09-16 00:01:31 +09:00
}
}