2025-11-02 15:43:43 +09:00
/*!
* CoreExecutor — JSON v0 → Execute ( boxed )
*
* Responsibility
* - Single entry to execute a MIR ( JSON ) payload under Gate ‑ C / Core policy .
* - Encapsulates : optional canonicalize , v1 - bridge try , v0 - parse fallback ,
* OOB strict observation , and rc mapping via MIR Interpreter .
*
* Notes
* - For now , execution uses the existing MIR Interpreter runner
* ( execute_mir_module_quiet_exit ) . Later we can swap internals to call
* the Core Dispatcher directly without touching callers .
* /
use super ::NyashRunner ;
2025-11-02 15:46:58 +09:00
use std ::io ::Write ;
2025-11-02 15:43:43 +09:00
2025-11-04 20:46:43 +09:00
pub fn run_json_v0 ( runner : & NyashRunner , json : & str ) -> i32 {
2025-11-02 15:46:58 +09:00
// Optional: direct Core Dispatcher via child nyash (boxed)
// Toggle: HAKO_CORE_DIRECT=1 (alias: NYASH_CORE_DIRECT)
let core_direct = std ::env ::var ( " HAKO_CORE_DIRECT " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " )
| | std ::env ::var ( " NYASH_CORE_DIRECT " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) ;
if core_direct {
2025-11-02 17:59:20 +09:00
// Only attempt Core-Direct when payload already looks like MIR(JSON v0)
2025-11-02 17:50:06 +09:00
// i.e., has functions/blocks keys. Stage‑ B Program(JSON v0) must go through bridge first.
let looks_like_mir = json . contains ( " \" functions \" " ) & & json . contains ( " \" blocks \" " ) ;
if looks_like_mir {
2025-11-02 17:59:20 +09:00
// In-proc prototype (opt-in): HAKO_CORE_DIRECT_INPROC=1 (alias NYASH_CORE_DIRECT_INPROC)
let core_direct_inproc = std ::env ::var ( " HAKO_CORE_DIRECT_INPROC " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " )
| | std ::env ::var ( " NYASH_CORE_DIRECT_INPROC " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) ;
if core_direct_inproc {
if let Some ( rc ) = try_run_core_direct_inproc ( runner , json ) { return rc ; }
eprintln! ( " [core-exec] direct Core (inproc) failed; trying child wrapper " ) ;
}
2025-11-02 17:50:06 +09:00
if let Some ( rc ) = try_run_core_direct ( json ) { return rc ; }
2025-11-02 17:59:20 +09:00
eprintln! ( " [core-exec] direct Core (child) failed; falling back to VM interpreter " ) ;
2025-11-02 15:46:58 +09:00
}
2025-11-02 17:50:06 +09:00
// else: skip direct Core and continue to bridge/VM path
2025-11-02 15:46:58 +09:00
}
2025-11-02 15:43:43 +09:00
let mut payload = json . to_string ( ) ;
2025-11-04 20:46:43 +09:00
// Fast-path: accept MIR(JSON v0) directly when it looks like a module (functions/blocks)
if payload . contains ( " \" functions \" " ) & & payload . contains ( " \" blocks \" " ) {
match super ::mir_json_v0 ::parse_mir_v0_to_module ( & payload ) {
Ok ( module ) = > {
super ::json_v0_bridge ::maybe_dump_mir ( & module ) ;
crate ::runner ::child_env ::pre_run_reset_oob_if_strict ( ) ;
let rc = runner . execute_mir_module_quiet_exit ( & module ) ;
if crate ::config ::env ::oob_strict_fail ( ) & & crate ::runtime ::observe ::oob_seen ( ) {
eprintln! ( " [gate-c][oob-strict] Out-of-bounds observed → exit(1) " ) ;
return 1 ;
}
return rc ;
}
Err ( e ) = > {
eprintln! ( " ❌ MIR JSON v0 parse error: {} " , e ) ;
return 1 ;
}
}
}
2025-11-02 17:50:06 +09:00
// Always try the v1 bridge first (Stage‑ B Program JSON → MIR module).
// This is no‑ op when input is already MIR(JSON v0) with functions/blocks.
if let Ok ( j ) = crate ::runner ::modes ::common_util ::core_bridge ::canonicalize_module_json ( & payload ) {
payload = j ;
}
match crate ::runner ::json_v1_bridge ::try_parse_v1_to_module ( & payload ) {
Ok ( Some ( module ) ) = > {
super ::json_v0_bridge ::maybe_dump_mir ( & module ) ;
// OOB strict: reset observation flag
crate ::runner ::child_env ::pre_run_reset_oob_if_strict ( ) ;
let rc = runner . execute_mir_module_quiet_exit ( & module ) ;
if crate ::config ::env ::oob_strict_fail ( ) & & crate ::runtime ::observe ::oob_seen ( ) {
eprintln! ( " [gate-c][oob-strict] Out-of-bounds observed → exit(1) " ) ;
2025-11-02 15:43:43 +09:00
return 1 ;
}
2025-11-02 17:50:06 +09:00
return rc ;
}
Ok ( None ) = > { /* fall through to v0 parse / execute */ }
Err ( e ) = > {
eprintln! ( " ❌ JSON v1 bridge error: {} " , e ) ;
return 1 ;
2025-11-02 15:43:43 +09:00
}
}
match super ::json_v0_bridge ::parse_json_v0_to_module ( & payload ) {
Ok ( module ) = > {
super ::json_v0_bridge ::maybe_dump_mir ( & module ) ;
crate ::runner ::child_env ::pre_run_reset_oob_if_strict ( ) ;
let rc = runner . execute_mir_module_quiet_exit ( & module ) ;
if crate ::config ::env ::oob_strict_fail ( ) & & crate ::runtime ::observe ::oob_seen ( ) {
eprintln! ( " [gate-c][oob-strict] Out-of-bounds observed → exit(1) " ) ;
return 1 ;
}
rc
}
Err ( e ) = > {
eprintln! ( " ❌ JSON v0 bridge error: {} " , e ) ;
1
}
}
}
2025-11-02 15:46:58 +09:00
fn try_run_core_direct ( json : & str ) -> Option < i32 > {
// Generate a temporary Hako program that includes the Core dispatcher
// and calls NyVmDispatcher.run(json), printing the numeric result.
let tmp_dir = std ::path ::Path ::new ( " tmp " ) ;
let _ = std ::fs ::create_dir_all ( tmp_dir ) ;
let script_path = tmp_dir . join ( " core_exec_direct.hako " ) ;
// Escape JSON into Hako string literal (simple backslash+quote escaping)
let mut j = String ::new ( ) ;
for ch in json . chars ( ) {
match ch {
'\\' = > j . push_str ( " \\ \\ " ) ,
'"' = > j . push_str ( " \\ \" " ) ,
_ = > j . push ( ch ) ,
}
}
let code = format! (
2025-11-02 17:50:06 +09:00
" include \" lang/src/vm/core/dispatcher.hako \" \n static box Main {{ method main(args) {{ local j= \" {} \" ; local r=NyVmDispatcher.run(j); return r }} }} \n " ,
2025-11-02 15:46:58 +09:00
j
) ;
if let Ok ( mut f ) = std ::fs ::File ::create ( & script_path ) {
let _ = f . write_all ( code . as_bytes ( ) ) ;
} else {
return None ;
}
// Determine nyash binary (current executable)
let exe = std ::env ::current_exe ( ) . ok ( ) ? ;
let mut cmd = std ::process ::Command ::new ( exe ) ;
crate ::runner ::child_env ::apply_core_wrapper_env ( & mut cmd ) ;
let out = cmd
. args ( [ " --backend " , " vm " , script_path . to_string_lossy ( ) . as_ref ( ) ] )
. output ( )
. ok ( ) ? ;
2025-11-02 17:50:06 +09:00
if ! out . stdout . is_empty ( ) {
let _ = std ::io ::stdout ( ) . write_all ( & out . stdout ) ;
2025-11-02 15:46:58 +09:00
}
2025-11-02 17:50:06 +09:00
let rc = out . status . code ( ) . unwrap_or ( 1 ) ;
Some ( rc )
2025-11-02 15:46:58 +09:00
}
2025-11-02 17:59:20 +09:00
fn try_run_core_direct_inproc ( runner : & NyashRunner , json : & str ) -> Option < i32 > {
// Parse MIR(JSON v0) in-proc and execute via MIR Interpreter quietly.
// This bypasses the child Hako wrapper and reduces latency/recursion risks.
match crate ::runner ::json_v0_bridge ::parse_json_v0_to_module ( json ) {
Ok ( module ) = > {
crate ::runner ::child_env ::pre_run_reset_oob_if_strict ( ) ;
let rc = runner . execute_mir_module_quiet_exit ( & module ) ;
if crate ::config ::env ::oob_strict_fail ( ) & & crate ::runtime ::observe ::oob_seen ( ) {
eprintln! ( " [gate-c][oob-strict] Out-of-bounds observed → exit(1) " ) ;
return Some ( 1 ) ;
}
Some ( rc )
}
Err ( _ ) = > None ,
}
}