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 ::* ;
use nyash_rust ::{ parser ::NyashParser , interpreter ::NyashInterpreter } ;
use std ::{ fs , process } ;
use std ::io ::Read ;
use std ::process ::Stdio ;
use std ::time ::{ Duration , Instant } ;
use std ::thread ::sleep ;
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 ;
// Read input source
let code = match fs ::read_to_string ( filename ) {
Ok ( c ) = > c ,
Err ( e ) = > { eprintln! ( " [ny-compiler] read error: {} " , e ) ; return false ; }
} ;
// Optional Phase-15: strip `using` lines and register modules (same policy as execute_nyash_file)
let enable_using = std ::env ::var ( " NYASH_ENABLE_USING " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) ;
let mut code_ref : std ::borrow ::Cow < '_ , str > = std ::borrow ::Cow ::Borrowed ( & code ) ;
if enable_using {
let mut out = String ::with_capacity ( code . len ( ) ) ;
let mut used_names : Vec < ( String , Option < String > ) > = Vec ::new ( ) ;
for line in code . lines ( ) {
let t = line . trim_start ( ) ;
if t . starts_with ( " using " ) {
if std ::env ::var ( " NYASH_CLI_VERBOSE " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
eprintln! ( " [using] stripped(line→selfhost): {} " , line ) ;
}
let rest0 = t . strip_prefix ( " using " ) . unwrap ( ) . trim ( ) ;
let rest0 = rest0 . strip_suffix ( ';' ) . unwrap_or ( rest0 ) . trim ( ) ;
let ( target , alias ) = if let Some ( pos ) = rest0 . find ( " as " ) {
( rest0 [ .. pos ] . trim ( ) . to_string ( ) , Some ( rest0 [ pos + 4 .. ] . trim ( ) . to_string ( ) ) )
} else { ( rest0 . to_string ( ) , None ) } ;
let is_path = target . starts_with ( '"' ) | | target . starts_with ( " ./ " ) | | target . starts_with ( '/' ) | | target . ends_with ( " .nyash " ) ;
if is_path {
let path = target . trim_matches ( '"' ) . to_string ( ) ;
let name = alias . clone ( ) . unwrap_or_else ( | | {
std ::path ::Path ::new ( & path ) . file_stem ( ) . and_then ( | s | s . to_str ( ) ) . unwrap_or ( " module " ) . to_string ( )
} ) ;
used_names . push ( ( name , Some ( path ) ) ) ;
} else {
used_names . push ( ( target , alias ) ) ;
}
continue ;
}
out . push_str ( line ) ;
out . push ( '\n' ) ;
}
// Register modules into minimal registry with best-effort path resolution
for ( ns_or_alias , alias_or_path ) in used_names {
if let Some ( path ) = alias_or_path {
let sb = crate ::box_trait ::StringBox ::new ( path ) ;
crate ::runtime ::modules_registry ::set ( ns_or_alias , Box ::new ( sb ) ) ;
} else {
let rel = format! ( " apps/ {} .nyash " , ns_or_alias . replace ( '.' , " / " ) ) ;
let exists = std ::path ::Path ::new ( & rel ) . exists ( ) ;
let path_or_ns = if exists { rel } else { ns_or_alias . clone ( ) } ;
let sb = crate ::box_trait ::StringBox ::new ( path_or_ns ) ;
crate ::runtime ::modules_registry ::set ( ns_or_alias , Box ::new ( sb ) ) ;
}
}
code_ref = std ::borrow ::Cow ::Owned ( out ) ;
}
// Write to tmp/ny_parser_input.ny (as expected by Ny parser v0), unless forced to reuse existing tmp
let use_tmp_only = std ::env ::var ( " NYASH_NY_COMPILER_USE_TMP_ONLY " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) ;
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 ;
}
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 ;
}
}
Err ( e ) = > { eprintln! ( " [ny-compiler] open tmp failed: {} " , e ) ; return false ; }
}
}
2025-09-16 14:57:05 +09:00
// Python MVP-first: prefer the lightweight harness to produce JSON v0
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 ) ;
cmd . arg ( py ) . arg ( & tmp_path ) ;
let out = match cmd . output ( ) { Ok ( o ) = > o , Err ( e ) = > { eprintln! ( " [ny-compiler] python harness failed to spawn: {} " , e ) ; return false ; } } ;
if out . status . success ( ) {
if let Ok ( line ) = String ::from_utf8 ( out . stdout ) . map ( | s | s . lines ( ) . next ( ) . unwrap_or ( " " ) . to_string ( ) ) {
if line . contains ( " \" version \" " ) & & line . contains ( " \" kind \" " ) {
match super ::json_v0_bridge ::parse_json_v0_to_module ( & line ) {
Ok ( module ) = > {
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 ; }
// Prefer PyVM for selfhost pipeline (parity reference)
if std ::env ::var ( " NYASH_VM_USE_PY " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
// Reuse the common PyVM runner path
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 ) ;
}
if std ::env ::var ( " NYASH_CLI_VERBOSE " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
eprintln! ( " [Bridge] using PyVM (selfhost-py) → {} " , mir_json_path . display ( ) ) ;
}
let entry = if module . functions . contains_key ( " Main.main " ) { " Main.main " } else if module . functions . contains_key ( " main " ) { " main " } else { " Main.main " } ;
let status = std ::process ::Command ::new ( & py3 )
. 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 ) ;
if ! status . success ( ) {
if std ::env ::var ( " NYASH_CLI_VERBOSE " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
eprintln! ( " ❌ PyVM (selfhost-py) failed (status= {} ) " , code ) ;
}
}
println! ( " Result: {} " , code ) ;
std ::process ::exit ( code ) ;
}
self . execute_mir_module ( & module ) ;
return true ;
}
Err ( e ) = > { eprintln! ( " [ny-compiler] json parse error: {} " , e ) ; return false ; }
}
}
}
}
}
}
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) ]
{ p . push ( " nyash_compiler.exe " ) ; }
#[ cfg(not(windows)) ]
{ p . push ( " nyash_compiler " ) ; }
if ! p . exists ( ) {
// Try PATH
if let Ok ( w ) = which ::which ( " nyash_compiler " ) { w } else { p }
} else { p }
} ;
if exe_path . exists ( ) {
let mut cmd = std ::process ::Command ::new ( & exe_path ) ;
// Prefer passing the original filename directly (parser EXE accepts positional path)
cmd . arg ( filename ) ;
// Gates
if std ::env ::var ( " NYASH_NY_COMPILER_MIN_JSON " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) { cmd . arg ( " --min-json " ) ; }
if std ::env ::var ( " NYASH_SELFHOST_READ_TMP " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) { cmd . arg ( " --read-tmp " ) ; }
2025-09-17 01:20:15 +09:00
if std ::env ::var ( " NYASH_NY_COMPILER_STAGE3 " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) { cmd . arg ( " --stage3 " ) ; }
2025-09-16 00:01:31 +09:00
if let Ok ( raw ) = std ::env ::var ( " NYASH_NY_COMPILER_CHILD_ARGS " ) { for tok in raw . split_whitespace ( ) { cmd . arg ( tok ) ; } }
let timeout_ms : u64 = std ::env ::var ( " NYASH_NY_COMPILER_TIMEOUT_MS " ) . ok ( ) . and_then ( | s | s . parse ( ) . ok ( ) ) . unwrap_or ( 2000 ) ;
let mut cmd = cmd . stdout ( Stdio ::piped ( ) ) . stderr ( Stdio ::piped ( ) ) ;
let mut child = match cmd . spawn ( ) { Ok ( c ) = > c , Err ( e ) = > { eprintln! ( " [ny-compiler] exe spawn failed: {} " , e ) ; return false ; } } ;
let mut ch_stdout = child . stdout . take ( ) ;
let mut ch_stderr = child . stderr . take ( ) ;
let start = Instant ::now ( ) ;
let mut timed_out = false ;
loop {
match child . try_wait ( ) {
Ok ( Some ( _status ) ) = > { break ; }
Ok ( None ) = > {
if start . elapsed ( ) > = Duration ::from_millis ( timeout_ms ) { let _ = child . kill ( ) ; let _ = child . wait ( ) ; timed_out = true ; break ; }
sleep ( Duration ::from_millis ( 10 ) ) ;
}
Err ( e ) = > { eprintln! ( " [ny-compiler] exe wait error: {} " , e ) ; return false ; }
}
}
let mut out_buf = Vec ::new ( ) ;
let mut err_buf = Vec ::new ( ) ;
if let Some ( mut s ) = ch_stdout { let _ = s . read_to_end ( & mut out_buf ) ; }
if let Some ( mut s ) = ch_stderr { let _ = s . read_to_end ( & mut err_buf ) ; }
if timed_out {
let head = String ::from_utf8_lossy ( & out_buf ) . chars ( ) . take ( 200 ) . collect ::< String > ( ) ;
eprintln! ( " [ny-compiler] exe timeout after {} ms; stdout(head)=' {} ' " , timeout_ms , head . replace ( '\n' , " \\ n " ) ) ;
return false ;
}
let stdout = match String ::from_utf8 ( out_buf ) { Ok ( s ) = > s , Err ( _ ) = > String ::new ( ) } ;
let mut json_line = String ::new ( ) ;
for line in stdout . lines ( ) { let t = line . trim ( ) ; if t . starts_with ( '{' ) & & t . contains ( " \" version \" " ) & & t . contains ( " \" kind \" " ) { json_line = t . to_string ( ) ; break ; } }
if json_line . is_empty ( ) {
if std ::env ::var ( " NYASH_CLI_VERBOSE " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
let head : String = stdout . chars ( ) . take ( 200 ) . collect ( ) ;
let errh : String = String ::from_utf8_lossy ( & err_buf ) . chars ( ) . take ( 200 ) . collect ( ) ;
eprintln! ( " [ny-compiler] exe produced no JSON; stdout(head)=' {} ' stderr(head)=' {} ' " , head . replace ( '\n' , " \\ n " ) , errh . replace ( '\n' , " \\ n " ) ) ;
}
return false ;
}
// Parse JSON v0 → MIR module
match super ::json_v0_bridge ::parse_json_v0_to_module ( & json_line ) {
Ok ( module ) = > {
println! ( " 🚀 Ny compiler EXE path (ny→json_v0) ON " ) ;
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 ;
} else {
2025-09-17 01:20:15 +09:00
// Prefer PyVM when requested (reference semantics), regardless of BoxCall presence
let prefer_pyvm = std ::env ::var ( " NYASH_VM_USE_PY " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) ;
if prefer_pyvm {
2025-09-16 00:01:31 +09:00
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 ) ;
}
if std ::env ::var ( " NYASH_CLI_VERBOSE " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
eprintln! ( " [Bridge] using PyVM (selfhost) → {} " , mir_json_path . display ( ) ) ;
}
let entry = if module . functions . contains_key ( " Main.main " ) { " Main.main " } else if module . functions . contains_key ( " main " ) { " main " } else { " Main.main " } ;
let status = std ::process ::Command ::new ( py3 )
. 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 ) ;
if ! status . success ( ) {
if std ::env ::var ( " NYASH_CLI_VERBOSE " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
eprintln! ( " ❌ PyVM (selfhost) failed (status= {} ) " , code ) ;
}
}
// Harmonize with interpreter path for smokes: print Result then exit code
println! ( " Result: {} " , code ) ;
std ::process ::exit ( code ) ;
}
}
}
self . execute_mir_module ( & module ) ;
return true ;
}
}
Err ( e ) = > { eprintln! ( " [ny-compiler] json parse error: {} " , e ) ; return false ; }
}
}
}
2025-09-16 14:57:05 +09:00
// Fallback: inline VM run (embed source into a tiny wrapper that prints JSON)
// This avoids CLI arg forwarding complexity and does not require FileBox.
2025-09-16 00:01:31 +09:00
let mut raw = String ::new ( ) ;
{
2025-09-16 14:57:05 +09:00
// Escape source for embedding as string literal
let mut esc = String ::with_capacity ( code_ref . len ( ) ) ;
for ch in code_ref . chars ( ) {
match ch {
'\\' = > esc . push_str ( " \\ \\ " ) ,
'"' = > esc . push_str ( " \\ \" " ) ,
'\n' = > esc . push_str ( " \n " ) ,
'\r' = > esc . push_str ( " " ) ,
_ = > esc . push ( ch ) ,
}
}
let inline_path = std ::path ::Path ::new ( " tmp " ) . join ( " inline_selfhost_emit.nyash " ) ;
let inline_code = format! (
2025-09-17 01:20:15 +09:00
" include \" apps/selfhost-compiler/boxes/parser_box.nyash \" \n include \" apps/selfhost-compiler/boxes/emitter_box.nyash \" \n static box Main {{ \n main(args) {{ \n local s = \" {} \" \n local p = new ParserBox() \n p.stage3_enable(1) \n local json = p.parse_program2(s) \n local e = new EmitterBox() \n json = e.emit_program(json, \" [] \" ) \n print(json) \n return 0 \n }} \n }} \n " ,
2025-09-16 14:57:05 +09:00
esc
) ;
if let Err ( e ) = std ::fs ::write ( & inline_path , inline_code ) {
eprintln! ( " [ny-compiler] write inline failed: {} " , e ) ;
return false ;
}
2025-09-16 00:01:31 +09:00
let exe = std ::env ::current_exe ( ) . unwrap_or_else ( | _ | std ::path ::PathBuf ::from ( " target/release/nyash " ) ) ;
let mut cmd = std ::process ::Command ::new ( exe ) ;
2025-09-16 14:57:05 +09:00
cmd . arg ( " --backend " ) . arg ( " vm " ) . arg ( & inline_path ) ;
2025-09-16 00:01:31 +09:00
cmd . env_remove ( " NYASH_USE_NY_COMPILER " ) ;
cmd . env_remove ( " NYASH_CLI_VERBOSE " ) ;
cmd . env ( " NYASH_JSON_ONLY " , " 1 " ) ;
let timeout_ms : u64 = std ::env ::var ( " NYASH_NY_COMPILER_TIMEOUT_MS " ) . ok ( ) . and_then ( | s | s . parse ( ) . ok ( ) ) . unwrap_or ( 2000 ) ;
let mut cmd = cmd . stdout ( Stdio ::piped ( ) ) . stderr ( Stdio ::piped ( ) ) ;
2025-09-16 14:57:05 +09:00
let mut child = match cmd . spawn ( ) { Ok ( c ) = > c , Err ( e ) = > { eprintln! ( " [ny-compiler] spawn inline vm failed: {} " , e ) ; return false ; } } ;
2025-09-16 00:01:31 +09:00
let mut ch_stdout = child . stdout . take ( ) ;
let mut ch_stderr = child . stderr . take ( ) ;
let start = Instant ::now ( ) ;
let mut timed_out = false ;
loop {
match child . try_wait ( ) {
2025-09-16 14:57:05 +09:00
Ok ( Some ( _ ) ) = > break ,
2025-09-16 00:01:31 +09:00
Ok ( None ) = > {
if start . elapsed ( ) > = Duration ::from_millis ( timeout_ms ) {
2025-09-16 14:57:05 +09:00
let _ = child . kill ( ) ; let _ = child . wait ( ) ; timed_out = true ; break ;
2025-09-16 00:01:31 +09:00
}
sleep ( Duration ::from_millis ( 10 ) ) ;
}
2025-09-16 14:57:05 +09:00
Err ( e ) = > { eprintln! ( " [ny-compiler] inline wait error: {} " , e ) ; break ; }
2025-09-16 00:01:31 +09:00
}
}
let mut out_buf = Vec ::new ( ) ;
if let Some ( mut s ) = ch_stdout { let _ = s . read_to_end ( & mut out_buf ) ; }
if timed_out {
let head = String ::from_utf8_lossy ( & out_buf ) . chars ( ) . take ( 200 ) . collect ::< String > ( ) ;
2025-09-16 14:57:05 +09:00
eprintln! ( " [ny-compiler] inline timeout after {} ms; stdout(head)=' {} ' " , timeout_ms , head . replace ( '\n' , " \\ n " ) ) ;
2025-09-16 00:01:31 +09:00
}
raw = String ::from_utf8_lossy ( & out_buf ) . to_string ( ) ;
}
let mut json_line = String ::new ( ) ;
for line in raw . lines ( ) {
let t = line . trim ( ) ;
if t . starts_with ( '{' ) & & t . contains ( " \" version \" " ) & & t . contains ( " \" kind \" " ) { json_line = t . to_string ( ) ; break ; }
}
if json_line . is_empty ( ) { return false ; }
match super ::json_v0_bridge ::parse_json_v0_to_module ( & json_line ) {
Ok ( module ) = > {
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-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.
let needs_pyvm = ! prefer_pyvm & & module . functions . values ( ) . any ( | f | {
2025-09-16 00:01:31 +09:00
f . blocks . values ( ) . any ( | bb | bb . instructions . iter ( ) . any ( | inst | matches! ( inst , crate ::mir ::MirInstruction ::BoxCall { .. } ) ) )
} ) ;
2025-09-16 14:57:05 +09:00
if prefer_pyvm | | needs_pyvm {
2025-09-16 00:01:31 +09:00
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 ) ;
}
if std ::env ::var ( " NYASH_CLI_VERBOSE " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
2025-09-16 14:57:05 +09:00
let mode = if prefer_pyvm { " selfhost " } else { " selfhost-fallback " } ;
eprintln! ( " [Bridge] using PyVM ( {} ) → {} " , mode , mir_json_path . display ( ) ) ;
2025-09-16 00:01:31 +09:00
}
let entry = if module . functions . contains_key ( " Main.main " ) { " Main.main " } else if module . functions . contains_key ( " main " ) { " main " } else { " Main.main " } ;
let status = std ::process ::Command ::new ( py3 )
. 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 ) ;
if ! status . success ( ) {
if std ::env ::var ( " NYASH_CLI_VERBOSE " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
eprintln! ( " ❌ PyVM (selfhost-fallback) failed (status= {} ) " , code ) ;
}
}
// Harmonize with interpreter path for smokes
println! ( " Result: {} " , code ) ;
std ::process ::exit ( code ) ;
}
}
}
self . execute_mir_module ( & module ) ;
true
}
Err ( e ) = > { eprintln! ( " ❌ JSON v0 bridge error: {} " , e ) ; false }
}
}
}