2025-08-26 04:34:14 +09:00
use super ::super ::NyashRunner ;
2025-11-21 06:25:17 +09:00
use nyash_rust ::{ ast ::ASTNode , mir ::MirCompiler , parser ::NyashParser } ;
2025-09-17 07:43:07 +09:00
use std ::{ fs , process } ;
2025-08-26 04:34:14 +09:00
2025-11-26 10:17:37 +09:00
// Phase 30 F-4.4: JoinIR VM Bridge dispatch (experimental)
2025-11-25 12:22:08 +09:00
// Used only when NYASH_JOINIR_EXPERIMENT=1 AND NYASH_JOINIR_VM_BRIDGE=1
2025-11-26 10:17:37 +09:00
use crate ::mir ::join_ir_vm_bridge_dispatch ::try_run_joinir_vm_bridge ;
2025-11-25 12:22:08 +09:00
2025-08-26 04:34:14 +09:00
impl NyashRunner {
2025-11-07 19:32:44 +09:00
/// Execute VM mode with full plugin initialization and AST prelude merge
2025-08-26 04:34:14 +09:00
pub ( crate ) fn execute_vm_mode ( & self , filename : & str ) {
2025-11-04 20:46:43 +09:00
// Note: hv1 direct route is now handled at main.rs entry point (before plugin initialization).
// This function is only called after plugin initialization has already occurred.
2025-11-04 16:33:04 +09:00
2025-09-15 18:44:49 +09:00
// Quiet mode for child pipelines (e.g., selfhost compiler JSON emit)
2025-11-06 15:41:52 +09:00
let quiet_pipe = crate ::config ::env ::env_bool ( " NYASH_JSON_ONLY " ) ;
2025-12-01 11:10:46 +09:00
if std ::env ::var ( " NYASH_EMIT_MIR_TRACE " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . debug ( & format! (
2025-12-01 11:10:46 +09:00
" [runner/vm] entry file={} quiet_pipe={} mode=stage-b?{} " ,
filename ,
quiet_pipe ,
std ::env ::var ( " HAKO_STAGEB_TRACE " )
. ok ( )
. unwrap_or_else ( | | " 0 " . to_string ( ) )
2025-12-02 23:27:41 +09:00
) ) ;
2025-12-01 11:10:46 +09:00
}
2025-11-07 19:32:44 +09:00
2025-09-08 01:08:59 +09:00
// Enforce plugin-first policy for VM on this branch (deterministic):
// - Initialize plugin host if not yet loaded
// - Prefer plugin implementations for core boxes
// - Optionally fail fast when plugins are missing (NYASH_VM_PLUGIN_STRICT=1)
{
2025-11-08 17:04:21 +09:00
// FileBox provider initialization (SSOT via ProviderFactory)
2025-11-08 15:13:22 +09:00
use crate ::runner ::modes ::common_util ::provider_registry ;
use nyash_rust ::runtime ::provider_lock ;
2025-11-08 17:04:21 +09:00
// Register builtin FileBox factory (idempotent)
#[ cfg(feature = " builtin-filebox " ) ]
{
nyash_rust ::boxes ::file ::builtin_factory ::register_builtin_filebox ( ) ;
}
// Select provider based on mode (dynamic → builtin → core-ro)
2025-11-08 15:13:22 +09:00
let filebox_mode = provider_registry ::read_filebox_mode_from_env ( ) ;
let filebox_provider = provider_registry ::select_file_provider ( filebox_mode ) ;
if let Err ( e ) = provider_lock ::set_filebox_provider ( filebox_provider ) {
if ! quiet_pipe {
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . warn ( & format! ( " [warn] FileBox provider already set: {} " , e ) ) ;
2025-11-08 15:13:22 +09:00
}
}
2025-09-08 01:08:59 +09:00
// Initialize unified registry globals (idempotent)
nyash_rust ::runtime ::init_global_unified_registry ( ) ;
2025-11-07 19:32:44 +09:00
2025-09-08 01:08:59 +09:00
// Init plugin host from nyash.toml if not yet loaded
let need_init = {
let host = nyash_rust ::runtime ::get_global_plugin_host ( ) ;
2025-09-17 07:43:07 +09:00
host . read ( )
. map ( | h | h . config_ref ( ) . is_none ( ) )
. unwrap_or ( true )
2025-09-08 01:08:59 +09:00
} ;
if need_init {
2025-11-06 15:41:52 +09:00
// Let init_bid_plugins resolve hakorune.toml/nyash.toml and configure
2025-09-08 01:08:59 +09:00
crate ::runner_plugin_init ::init_bid_plugins ( ) ;
}
2025-11-07 19:32:44 +09:00
2025-11-08 17:04:21 +09:00
// Phase 21.4: Deprecation warnings for old ENV variables
// No longer auto-setting NYASH_USE_PLUGIN_BUILTINS or NYASH_PLUGIN_OVERRIDE_TYPES
// Use NYASH_BOX_FACTORY_POLICY and NYASH_FILEBOX_MODE instead
if std ::env ::var ( " NYASH_USE_PLUGIN_BUILTINS " ) . is_ok ( ) {
if ! quiet_pipe {
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . warn ( " [vm] warn: NYASH_USE_PLUGIN_BUILTINS is deprecated. Use NYASH_BOX_FACTORY_POLICY instead. " ) ;
2025-11-08 17:04:21 +09:00
}
2025-09-08 01:08:59 +09:00
}
2025-11-08 17:04:21 +09:00
if std ::env ::var ( " NYASH_PLUGIN_OVERRIDE_TYPES " ) . is_ok ( ) {
if ! quiet_pipe {
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . warn ( " [vm] warn: NYASH_PLUGIN_OVERRIDE_TYPES is deprecated. Use NYASH_BOX_FACTORY_POLICY instead. " ) ;
2025-09-17 07:43:07 +09:00
}
2025-09-08 01:08:59 +09:00
}
2025-11-08 00:46:34 +09:00
// Centralized plugin guard
let strict = crate ::config ::env ::env_bool ( " NYASH_VM_PLUGIN_STRICT " ) ;
crate ::runner ::modes ::common_util ::plugin_guard ::check_and_report (
2025-11-21 06:25:17 +09:00
strict , quiet_pipe , " vm " ,
2025-11-08 00:46:34 +09:00
) ;
2025-09-08 01:08:59 +09:00
}
2025-08-26 04:34:14 +09:00
// Read the file
let code = match fs ::read_to_string ( filename ) {
Ok ( content ) = > content ,
2025-09-17 07:43:07 +09:00
Err ( e ) = > {
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . error ( & format! ( " ❌ Error reading file {} : {} " , filename , e ) ) ;
2025-09-17 07:43:07 +09:00
process ::exit ( 1 ) ;
}
2025-08-26 04:34:14 +09:00
} ;
2025-11-07 21:04:01 +09:00
// Unified using/prelude handling (SSOT):
// - resolve_prelude_paths_profiled: discover preludes (DFS, operator boxes, etc.)
// - merge_prelude_text: text-based merge for all VM paths
// * .hako プレリュードは AST に突っ込まない( Parse error防止)
// * .hako は text-merge + Stage-3 parser で一貫処理
let trace = crate ::config ::env ::cli_verbose ( )
| | crate ::config ::env ::env_bool ( " NYASH_RESOLVE_TRACE " ) ;
// When using is enabled, resolve preludes/profile; otherwise, keep original code.
let mut code_final = if crate ::config ::env ::enable_using ( ) {
2025-11-07 19:32:44 +09:00
match crate ::runner ::modes ::common_util ::resolve ::resolve_prelude_paths_profiled (
2025-11-21 06:25:17 +09:00
self , & code , filename ,
2025-11-01 13:28:56 +09:00
) {
2025-11-07 21:04:01 +09:00
Ok ( ( _ , prelude_paths ) ) = > {
if ! prelude_paths . is_empty ( ) {
// SSOT: always text-merge for VM (includes .hako-safe handling inside)
match crate ::runner ::modes ::common_util ::resolve ::merge_prelude_text (
2025-11-21 06:25:17 +09:00
self , & code , filename ,
2025-11-07 21:04:01 +09:00
) {
2025-11-07 19:32:44 +09:00
Ok ( merged ) = > {
2025-11-07 21:04:01 +09:00
if trace {
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . debug ( & format! (
2025-11-07 21:04:01 +09:00
" [using/text-merge] preludes={} (vm) " ,
prelude_paths . len ( )
2025-12-02 23:27:41 +09:00
) ) ;
2025-11-07 21:04:01 +09:00
}
merged
}
Err ( e ) = > {
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . error ( & format! ( " ❌ {} " , e ) ) ;
2025-11-07 21:04:01 +09:00
process ::exit ( 1 ) ;
2025-11-07 19:32:44 +09:00
}
}
2025-11-07 21:04:01 +09:00
} else {
code . clone ( )
2025-11-07 19:32:44 +09:00
}
2025-11-01 13:28:56 +09:00
}
Err ( e ) = > {
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . error ( & format! ( " ❌ {} " , e ) ) ;
2025-11-01 13:28:56 +09:00
process ::exit ( 1 ) ;
2025-09-26 00:27:02 +09:00
}
2025-09-18 06:35:49 +09:00
}
2025-11-04 16:33:04 +09:00
} else {
// using disabled: detect and fail fast if present
if code . contains ( " \n using " ) | | code . trim_start ( ) . starts_with ( " using " ) {
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . error ( " ❌ using: prelude merge is disabled in this profile. Enable NYASH_USING_AST=1 or remove 'using' lines. " ) ;
2025-11-04 16:33:04 +09:00
process ::exit ( 1 ) ;
}
2025-11-07 21:04:01 +09:00
code
} ;
2025-09-18 06:35:49 +09:00
2025-11-07 19:32:44 +09:00
// Dev sugar pre-expand: @name = expr → local name = expr
2025-11-21 06:25:17 +09:00
code_final = crate ::runner ::modes ::common_util ::resolve ::preexpand_at_local ( & code_final ) ;
2025-11-04 16:33:04 +09:00
2025-11-07 19:32:44 +09:00
// Hako-friendly normalize: strip leading `local ` at line head for Nyash parser compatibility.
2025-11-07 21:04:01 +09:00
if crate ::runner ::modes ::common_util ::hako ::looks_like_hako_code ( & code_final )
| | filename . ends_with ( " .hako " )
{
2025-11-21 06:25:17 +09:00
code_final = crate ::runner ::modes ::common_util ::hako ::strip_local_decl ( & code_final ) ;
2025-11-07 21:04:01 +09:00
}
2025-11-15 22:32:13 +09:00
// Optional: dump merged Hako source after using/prelude merge and Hako normalization.
// Guarded by env; defaultはOFF( Phase 25.1a selfhost builder デバッグ用)。
2025-11-21 06:25:17 +09:00
if std ::env ::var ( " NYASH_VM_DUMP_MERGED_HAKO " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
2025-11-15 22:32:13 +09:00
let default_path = {
let mut tmp = std ::env ::temp_dir ( ) ;
tmp . push ( " nyash_merged_vm.hako " ) ;
tmp
} ;
let path = std ::env ::var ( " NYASH_VM_DUMP_MERGED_HAKO_PATH " )
. ok ( )
. filter ( | p | ! p . is_empty ( ) )
. unwrap_or_else ( | | default_path . to_string_lossy ( ) . into_owned ( ) ) ;
if let Err ( e ) = fs ::write ( & path , & code_final ) {
if trace {
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . warn ( & format! ( " [vm/merged-hako] failed to write {} : {} " , path , e ) ) ;
2025-11-15 22:32:13 +09:00
}
2025-11-21 06:25:17 +09:00
} else if trace | | crate ::config ::env ::env_bool ( " NYASH_VM_DUMP_MERGED_HAKO_LOG " ) {
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . debug ( & format! ( " [vm/merged-hako] dumped merged code to {} " , path ) ) ;
2025-11-15 22:32:13 +09:00
}
}
2025-11-30 14:30:28 +09:00
if trace & & crate ::config ::env ::parser_stage3_enabled ( ) {
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . debug ( & format! (
2025-12-01 11:10:46 +09:00
" [vm] Stage-3: enabled (NYASH_FEATURES/legacy env) for {} " ,
filename
2025-12-02 23:27:41 +09:00
) ) ;
2025-11-04 16:33:04 +09:00
}
2025-11-07 19:32:44 +09:00
// Fail‑ Fast (opt‑ in): Hako 構文を Nyash VM 経路で実行しない
// 目的: .hako は Hakorune VM、MIR は Core/LLVM に役割分離するためのガード
2025-11-04 16:33:04 +09:00
{
2025-11-07 19:32:44 +09:00
let on = crate ::runner ::modes ::common_util ::hako ::fail_fast_on_hako ( ) ;
if on {
let hako_like = code_final . contains ( " static box " )
| | code_final . contains ( " using selfhost. " )
| | code_final . contains ( " using hakorune. " ) ;
if hako_like {
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . error ( " ❌ Hako-like source detected in Nyash VM path. Use Hakorune VM (v1 dispatcher) or Core/LLVM for MIR. \n hint: set HAKO_VERIFY_PRIMARY=hakovm in verify path " ) ;
2025-11-07 19:32:44 +09:00
process ::exit ( 1 ) ;
}
2025-11-01 21:48:12 +09:00
}
}
2025-11-07 19:32:44 +09:00
2025-11-07 21:04:01 +09:00
// Parse main code (after text-merge and Hako normalization)
let ast_combined = match NyashParser ::parse_from_string ( & code_final ) {
2025-08-26 04:34:14 +09:00
Ok ( ast ) = > ast ,
2025-09-17 07:43:07 +09:00
Err ( e ) = > {
2025-11-21 06:25:17 +09:00
crate ::runner ::modes ::common_util ::diag ::print_parse_error_with_context (
2025-11-24 14:17:02 +09:00
filename ,
& code_final ,
& e ,
2025-11-21 06:25:17 +09:00
) ;
2025-11-14 13:36:20 +09:00
// Enhanced context: list merged prelude files if any
2025-11-21 06:25:17 +09:00
let preludes =
crate ::runner ::modes ::common_util ::resolve ::clone_last_merged_preludes ( ) ;
2025-11-14 13:36:20 +09:00
if ! preludes . is_empty ( ) {
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . debug ( & format! ( " [parse/context] merged prelude files ( {} ): " , preludes . len ( ) ) ) ;
2025-11-14 13:36:20 +09:00
let show = std ::cmp ::min ( 16 , preludes . len ( ) ) ;
for p in preludes . iter ( ) . take ( show ) {
2025-12-02 23:27:41 +09:00
ring0 . log . debug ( & format! ( " - {} " , p ) ) ;
2025-11-14 13:36:20 +09:00
}
if preludes . len ( ) > show {
2025-12-02 23:27:41 +09:00
ring0 . log . debug ( & format! ( " ... ( {} more) " , preludes . len ( ) - show ) ) ;
2025-11-14 13:36:20 +09:00
}
}
2025-09-17 07:43:07 +09:00
process ::exit ( 1 ) ;
}
2025-08-26 04:34:14 +09:00
} ;
2025-11-07 19:32:44 +09:00
// Optional: dump AST statement kinds for quick diagnostics
if std ::env ::var ( " NYASH_AST_DUMP " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . debug ( " [ast] dump start (vm) " ) ;
2025-11-07 19:32:44 +09:00
if let ASTNode ::Program { statements , .. } = & ast_combined {
for ( i , st ) in statements . iter ( ) . enumerate ( ) . take ( 50 ) {
let kind = match st {
ASTNode ::BoxDeclaration {
is_static , name , ..
} = > {
if * is_static {
format! ( " StaticBox( {} ) " , name )
} else {
format! ( " Box( {} ) " , name )
}
}
ASTNode ::FunctionDeclaration { name , .. } = > format! ( " FuncDecl( {} ) " , name ) ,
ASTNode ::FunctionCall { name , .. } = > format! ( " FuncCall( {} ) " , name ) ,
ASTNode ::MethodCall { method , .. } = > format! ( " MethodCall( {} ) " , method ) ,
ASTNode ::ScopeBox { .. } = > " ScopeBox " . to_string ( ) ,
ASTNode ::ImportStatement { path , .. } = > format! ( " Import( {} ) " , path ) ,
ASTNode ::UsingStatement { namespace_name , .. } = > {
format! ( " Using( {} ) " , namespace_name )
}
_ = > format! ( " {:?} " , st ) ,
} ;
2025-12-02 23:27:41 +09:00
ring0 . log . debug ( & format! ( " [ast] {} : {} " , i , kind ) ) ;
2025-11-07 19:32:44 +09:00
}
2025-08-27 17:06:46 +09:00
}
2025-12-02 23:27:41 +09:00
ring0 . log . debug ( " [ast] dump end " ) ;
2025-11-07 19:32:44 +09:00
}
// Macro expand (if enabled)
let ast = crate ::r#macro ::maybe_expand_and_dump ( & ast_combined , false ) ;
// Minimal user-defined Box support (inline factory)
let static_box_decls = {
use crate ::{
box_factory ::{ BoxFactory , RuntimeError } ,
core ::model ::BoxDeclaration as CoreBoxDecl ,
instance_v2 ::InstanceBox ,
} ;
use std ::sync ::{ Arc , RwLock } ;
// Collect user-defined (non-static) box declarations at program level.
// Additionally, record static box names so we can alias
// `StaticBoxName` -> `StaticBoxNameInstance` when such a
// concrete instance box exists (common pattern in libs).
// Also collect static box declarations for VM singleton persistence.
let mut nonstatic_decls : std ::collections ::HashMap < String , CoreBoxDecl > =
std ::collections ::HashMap ::new ( ) ;
let mut static_names : Vec < String > = Vec ::new ( ) ;
let mut static_box_decls : std ::collections ::HashMap < String , CoreBoxDecl > =
std ::collections ::HashMap ::new ( ) ;
if let ASTNode ::Program { statements , .. } = & ast {
for st in statements {
if let ASTNode ::BoxDeclaration {
name ,
fields ,
public_fields ,
private_fields ,
methods ,
constructors ,
init_fields ,
weak_fields ,
is_interface ,
extends ,
implements ,
type_parameters ,
is_static ,
..
2025-11-21 06:25:17 +09:00
} = st
{
2025-11-07 19:32:44 +09:00
if * is_static {
static_names . push ( name . clone ( ) ) ;
// Store static box declaration for VM singleton persistence
let static_decl = CoreBoxDecl {
name : name . clone ( ) ,
fields : fields . clone ( ) ,
public_fields : public_fields . clone ( ) ,
private_fields : private_fields . clone ( ) ,
methods : methods . clone ( ) ,
constructors : constructors . clone ( ) ,
init_fields : init_fields . clone ( ) ,
weak_fields : weak_fields . clone ( ) ,
is_interface : * is_interface ,
extends : extends . clone ( ) ,
implements : implements . clone ( ) ,
type_parameters : type_parameters . clone ( ) ,
} ;
static_box_decls . insert ( name . clone ( ) , static_decl ) ;
continue ; // modules/static boxes are not user-instantiable directly
}
let decl = CoreBoxDecl {
name : name . clone ( ) ,
fields : fields . clone ( ) ,
public_fields : public_fields . clone ( ) ,
private_fields : private_fields . clone ( ) ,
methods : methods . clone ( ) ,
constructors : constructors . clone ( ) ,
init_fields : init_fields . clone ( ) ,
weak_fields : weak_fields . clone ( ) ,
is_interface : * is_interface ,
extends : extends . clone ( ) ,
implements : implements . clone ( ) ,
type_parameters : type_parameters . clone ( ) ,
} ;
nonstatic_decls . insert ( name . clone ( ) , decl ) ;
}
}
}
2025-11-17 02:38:54 +09:00
// Phase 25.1b: Include static boxes in user factory for NewBox support
// Static boxes are singletons (via VM's register_static_box_decl) but must also
// be advertised by user factory so NewBox doesn't fall through to plugin route.
//
// Build final map:
// 1. Start with nonstatic_decls (regular user boxes)
// 2. Add static_box_decls (for NewBox support, VM will ensure singleton)
// 3. Add StaticName -> StaticNameInstance aliases if present
2025-11-07 19:32:44 +09:00
let mut decls = nonstatic_decls . clone ( ) ;
2025-11-17 02:38:54 +09:00
// Add static box declarations (VM singleton instances)
// nonstatic takes precedence if name conflicts (rare but possible)
for ( name , sdecl ) in static_box_decls . iter ( ) {
if ! decls . contains_key ( name ) {
decls . insert ( name . clone ( ) , sdecl . clone ( ) ) ;
}
}
// Add StaticName -> StaticNameInstance aliases if present
2025-11-07 19:32:44 +09:00
for s in static_names . into_iter ( ) {
let inst = format! ( " {} Instance " , s ) ;
if let Some ( d ) = nonstatic_decls . get ( & inst ) {
decls . insert ( s , d . clone ( ) ) ;
}
}
if ! decls . is_empty ( ) {
// Inline factory: minimal User factory backed by collected declarations
struct InlineUserBoxFactory {
decls : Arc < RwLock < std ::collections ::HashMap < String , CoreBoxDecl > > > ,
}
impl BoxFactory for InlineUserBoxFactory {
fn create_box (
& self ,
name : & str ,
args : & [ Box < dyn crate ::box_trait ::NyashBox > ] ,
2025-11-21 06:25:17 +09:00
) -> Result < Box < dyn crate ::box_trait ::NyashBox > , RuntimeError >
{
2025-11-25 08:44:31 +09:00
let guard = self . decls . read ( ) . unwrap ( ) ;
let opt = guard . get ( name ) . cloned ( ) ;
2025-11-07 19:32:44 +09:00
let decl = match opt {
2025-11-25 08:44:31 +09:00
Some ( d ) = > {
drop ( guard ) ;
d
}
2025-11-07 19:32:44 +09:00
None = > {
2025-11-25 08:44:31 +09:00
// Quick Win 1: Show available boxes for easier debugging
let mut available : Vec < _ > = guard . keys ( ) . cloned ( ) . collect ( ) ;
available . sort ( ) ;
drop ( guard ) ;
let hint = if available . is_empty ( ) {
" No user-defined boxes available " . to_string ( )
} else if available . len ( ) < = 10 {
format! ( " Available: {} " , available . join ( " , " ) )
} else {
format! (
" Available ({} boxes): {}, ... " ,
available . len ( ) ,
available [ .. 10 ] . join ( " , " )
)
} ;
2025-11-07 19:32:44 +09:00
return Err ( RuntimeError ::InvalidOperation {
2025-11-25 08:44:31 +09:00
message : format ! ( " Unknown Box type: {}. {} " , name , hint ) ,
} ) ;
2025-11-07 19:32:44 +09:00
}
} ;
let mut inst = InstanceBox ::from_declaration (
decl . name . clone ( ) ,
decl . fields . clone ( ) ,
decl . methods . clone ( ) ,
) ;
let _ = inst . init ( args ) ;
Ok ( Box ::new ( inst ) )
}
fn box_types ( & self ) -> Vec < & str > {
2025-11-17 02:38:54 +09:00
// Can't return borrowed strings from temporary RwLock guard
// Registry will try create_box() regardless of this list
2025-11-07 19:32:44 +09:00
vec! [ ]
}
fn is_available ( & self ) -> bool {
true
}
fn factory_type ( & self ) -> crate ::box_factory ::FactoryType {
crate ::box_factory ::FactoryType ::User
}
}
let factory = InlineUserBoxFactory {
decls : Arc ::new ( RwLock ::new ( decls ) ) ,
} ;
2025-11-21 06:25:17 +09:00
crate ::runtime ::unified_registry ::register_user_defined_factory (
std ::sync ::Arc ::new ( factory ) ,
) ;
2025-09-17 07:43:07 +09:00
}
2025-11-07 19:32:44 +09:00
// Return static_box_decls for VM registration
static_box_decls
2025-08-26 04:34:14 +09:00
} ;
2025-11-07 19:32:44 +09:00
// Compile to MIR
let mut compiler = MirCompiler ::with_options ( ! self . config . no_optimize ) ;
2025-11-24 14:17:02 +09:00
let compile = match crate ::runner ::modes ::common_util ::source_hint ::compile_with_source_hint (
& mut compiler ,
ast ,
Some ( filename ) ,
) {
2025-11-07 19:32:44 +09:00
Ok ( c ) = > c ,
2025-09-17 07:43:07 +09:00
Err ( e ) = > {
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . error ( & format! ( " ❌ MIR compilation error: {} " , e ) ) ;
2025-09-17 07:43:07 +09:00
process ::exit ( 1 ) ;
}
2025-08-26 04:34:14 +09:00
} ;
2025-11-07 19:32:44 +09:00
// Optional barrier-elision for parity with fallback path
let mut module_vm = compile . module . clone ( ) ;
if crate ::config ::env ::env_bool ( " NYASH_VM_ESCAPE_ANALYSIS " ) {
let removed = crate ::mir ::passes ::escape ::escape_elide_barriers_vm ( & mut module_vm ) ;
if removed > 0 {
2025-11-21 06:25:17 +09:00
crate ::cli_v! ( " [VM] escape_elide_barriers: removed {} barriers " , removed ) ;
2025-08-27 17:06:46 +09:00
}
}
2025-09-06 06:24:08 +09:00
// Optional: dump MIR for diagnostics
2025-11-24 18:19:31 +09:00
// Phase 25.1: File dump for offline analysis (ParserBox等)
if let Ok ( path ) = std ::env ::var ( " RUST_MIR_DUMP_PATH " ) {
if let Ok ( mut f ) = std ::fs ::File ::create ( & path ) {
let p = crate ::mir ::MirPrinter ::new ( ) ;
let _ = std ::io ::Write ::write_all ( & mut f , p . print_module ( & module_vm ) . as_bytes ( ) ) ;
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . info ( & format! ( " [vm] MIR dumped to: {} " , path ) ) ;
2025-11-24 18:19:31 +09:00
}
}
// Existing: NYASH_VM_DUMP_MIR dumps to stderr
2025-11-06 15:41:52 +09:00
if crate ::config ::env ::env_bool ( " NYASH_VM_DUMP_MIR " ) {
2025-11-07 19:32:44 +09:00
let p = crate ::mir ::MirPrinter ::new ( ) ;
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . debug ( & p . print_module ( & module_vm ) ) ;
2025-09-06 06:24:08 +09:00
}
2025-11-07 19:32:44 +09:00
// Execute via MIR interpreter
use crate ::backend ::MirInterpreter ;
let mut vm = MirInterpreter ::new ( ) ;
// Register static box declarations for singleton persistence
for ( name , decl ) in static_box_decls {
vm . register_static_box_decl ( name , decl ) ;
2025-08-31 03:03:04 +09:00
}
2025-11-07 19:32:44 +09:00
// Optional: verify MIR before execution (dev-only)
if crate ::config ::env ::env_bool ( " NYASH_VM_VERIFY_MIR " ) {
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
2025-11-07 19:32:44 +09:00
let mut verifier = crate ::mir ::verification ::MirVerifier ::new ( ) ;
for ( name , func ) in module_vm . functions . iter ( ) {
if let Err ( errors ) = verifier . verify_function ( func ) {
if ! errors . is_empty ( ) {
2025-12-02 23:27:41 +09:00
ring0 . log . warn ( & format! ( " [vm-verify] function: {} " , name ) ) ;
2025-11-07 19:32:44 +09:00
for er in errors {
2025-12-02 23:27:41 +09:00
ring0 . log . warn ( & format! ( " • {} " , er ) ) ;
2025-11-07 19:32:44 +09:00
}
2025-09-24 21:45:27 +09:00
}
}
2025-09-14 04:51:33 +09:00
}
}
2025-11-07 19:32:44 +09:00
if std ::env ::var ( " NYASH_DUMP_FUNCS " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . debug ( " [vm] functions available: " ) ;
2025-11-07 19:32:44 +09:00
for k in module_vm . functions . keys ( ) {
2025-12-02 23:27:41 +09:00
ring0 . log . debug ( & format! ( " - {} " , k ) ) ;
2025-11-07 19:32:44 +09:00
}
}
2025-09-01 23:44:34 +09:00
2025-11-27 17:05:46 +09:00
// Phase 33-10.0: If lowering ドライラン統合(箱化版)
2025-11-30 14:30:28 +09:00
// JoinIR dev + IfSelect 有効時に IfLoweringDryRunner を使用
if crate ::config ::env ::joinir_dev_enabled ( )
& & crate ::config ::env ::joinir_if_select_enabled ( )
{
2025-11-27 17:05:46 +09:00
let debug_level = crate ::config ::env ::joinir_debug_level ( ) ;
2025-11-28 17:42:19 +09:00
let runner =
crate ::mir ::join_ir ::lowering ::if_dry_runner ::IfLoweringDryRunner ::new ( debug_level ) ;
2025-11-27 17:05:46 +09:00
let stats = runner . scan_module ( & module_vm . functions ) ;
runner . print_stats ( & stats ) ;
}
2025-11-26 10:17:37 +09:00
// Phase 30 F-4.4: JoinIR VM Bridge experimental path (consolidated dispatch)
2025-11-25 12:22:08 +09:00
// Activated when NYASH_JOINIR_EXPERIMENT=1 AND NYASH_JOINIR_VM_BRIDGE=1
2025-11-26 10:17:37 +09:00
// Routing logic is centralized in join_ir_vm_bridge_dispatch module
try_run_joinir_vm_bridge ( & module_vm , quiet_pipe ) ;
2025-11-25 12:22:08 +09:00
2025-12-01 11:10:46 +09:00
if std ::env ::var ( " NYASH_EMIT_MIR_TRACE " )
. ok ( )
. as_deref ( )
= = Some ( " 1 " )
{
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . debug ( " [runner/vm] calling execute_module " ) ;
2025-12-01 11:10:46 +09:00
}
2025-08-31 03:03:04 +09:00
match vm . execute_module ( & module_vm ) {
2025-11-07 19:32:44 +09:00
Ok ( ret ) = > {
2025-11-21 06:25:17 +09:00
use crate ::box_trait ::{ BoolBox , IntegerBox } ;
2025-11-07 19:32:44 +09:00
2025-12-01 11:10:46 +09:00
if std ::env ::var ( " NYASH_EMIT_MIR_TRACE " )
. ok ( )
. as_deref ( )
= = Some ( " 1 " )
{
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . debug ( & format! ( " [runner/vm] vm_result= {} " , ret . to_string_box ( ) . value ) ) ;
2025-12-01 11:10:46 +09:00
}
2025-11-07 19:32:44 +09:00
// Extract exit code from return value
let exit_code = if let Some ( ib ) = ret . as_any ( ) . downcast_ref ::< IntegerBox > ( ) {
ib . value as i32
} else if let Some ( bb ) = ret . as_any ( ) . downcast_ref ::< BoolBox > ( ) {
2025-11-21 06:25:17 +09:00
if bb . value {
1
} else {
0
}
2025-08-28 22:31:51 +09:00
} else {
2025-11-07 19:32:44 +09:00
// For non-integer/bool returns, default to 0 (success)
0
2025-09-08 01:08:59 +09:00
} ;
2025-11-07 19:32:44 +09:00
2025-11-11 02:07:12 +09:00
// Optional: print lightweight VM counters for diagnostics
if crate ::config ::env ::env_bool ( " NYASH_VM_STATS " ) {
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
2025-11-11 02:07:12 +09:00
let ( inst , br , cmp ) = vm . stats_counters ( ) ;
2025-12-02 23:27:41 +09:00
ring0 . log . debug ( & format! ( " [vm/stats] inst= {} compare= {} branch= {} " , inst , cmp , br ) ) ;
2025-11-11 02:07:12 +09:00
}
2025-11-07 19:32:44 +09:00
// Quiet mode: suppress "RC:" output for JSON-only pipelines
2025-09-15 18:44:49 +09:00
if ! quiet_pipe {
2025-12-03 11:17:41 +09:00
// Phase 98: ConsoleService if available, otherwise eprintln
2025-12-03 13:59:06 +09:00
// Phase 103: Handle Option<Arc<dyn ConsoleService>>
2025-12-03 11:04:58 +09:00
if let Some ( host ) = crate ::runtime ::try_get_core_plugin_host ( ) {
2025-12-03 13:59:06 +09:00
if let Some ( ref console ) = host . core . console {
console . println ( & format! ( " RC: {} " , exit_code ) ) ;
} else {
println! ( " RC: {} " , exit_code ) ;
}
2025-12-03 11:04:58 +09:00
} else {
println! ( " RC: {} " , exit_code ) ;
}
2025-09-15 18:44:49 +09:00
}
2025-12-01 11:10:46 +09:00
if std ::env ::var ( " NYASH_EMIT_MIR_TRACE " )
. ok ( )
. as_deref ( )
= = Some ( " 1 " )
{
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
ring0 . log . debug ( & format! ( " [runner/vm] exit_code= {} " , exit_code ) ) ;
2025-12-01 11:10:46 +09:00
}
2025-11-07 19:32:44 +09:00
// Exit with the return value as exit code
process ::exit ( exit_code ) ;
2025-09-17 07:43:07 +09:00
}
Err ( e ) = > {
2025-12-02 23:27:41 +09:00
let ring0 = crate ::runtime ::ring0 ::get_global_ring0 ( ) ;
2025-12-01 11:10:46 +09:00
if std ::env ::var ( " NYASH_EMIT_MIR_TRACE " )
. ok ( )
. as_deref ( )
= = Some ( " 1 " )
{
2025-12-02 23:27:41 +09:00
ring0 . log . debug ( & format! ( " [runner/vm] vm_error= {} " , e ) ) ;
2025-12-01 11:10:46 +09:00
}
2025-12-02 23:27:41 +09:00
ring0 . log . error ( & format! ( " ❌ [rust-vm] VM error: {} " , e ) ) ;
2025-09-17 07:43:07 +09:00
process ::exit ( 1 ) ;
}
2025-08-26 04:34:14 +09:00
}
}
}