use super::super::NyashRunner; use nyash_rust::mir::passes::method_id_inject::inject_method_ids; use nyash_rust::{ mir::{MirCompiler, MirInstruction}, parser::NyashParser, }; use std::{fs, process}; impl NyashRunner { /// Execute LLVM mode (split) pub(crate) fn execute_llvm_mode(&self, filename: &str) { // Initialize plugin host so method_id injection can resolve plugin calls crate::runner_plugin_init::init_bid_plugins(); // Friendly plugin guard (non‑strict): unify diagnostics across modes crate::runner::modes::common_util::plugin_guard::check_and_report( false, crate::config::env::env_bool("NYASH_JSON_ONLY"), "llvm", ); // Read the file let code = match fs::read_to_string(filename) { Ok(content) => content, Err(e) => { eprintln!("❌ Error reading file {}: {}", filename, e); process::exit(1); } }; // Using handling (AST prelude merge like common/vm paths) let use_ast = crate::config::env::using_ast_enabled(); let mut code_ref: &str = &code; let cleaned_code_owned; let mut prelude_asts: Vec = Vec::new(); if crate::config::env::enable_using() { match crate::runner::modes::common_util::resolve::resolve_prelude_paths_profiled( self, &code, filename, ) { Ok((clean, paths)) => { cleaned_code_owned = clean; code_ref = &cleaned_code_owned; if !paths.is_empty() && !use_ast { eprintln!("❌ using: AST prelude merge is disabled in this profile. Enable NYASH_USING_AST=1 or remove 'using' lines."); std::process::exit(1); } if use_ast && !paths.is_empty() { match crate::runner::modes::common_util::resolve::parse_preludes_to_asts( self, &paths, ) { Ok(v) => prelude_asts = v, Err(e) => { eprintln!("❌ {}", e); std::process::exit(1); } } } } Err(e) => { eprintln!("❌ {}", e); process::exit(1); } } } // Pre-expand '@name[:T] = expr' sugar at line-head (same as common path) let preexpanded_owned = crate::runner::modes::common_util::resolve::preexpand_at_local(code_ref); code_ref = &preexpanded_owned; // Parse to AST (main) let main_ast = match NyashParser::parse_from_string(code_ref) { Ok(ast) => ast, Err(e) => { crate::runner::modes::common_util::diag::print_parse_error_with_context( filename, code_ref, &e, ); // Enhanced context: list merged prelude files if any (from text-merge path) let preludes = crate::runner::modes::common_util::resolve::clone_last_merged_preludes(); if !preludes.is_empty() { eprintln!("[parse/context] merged prelude files ({}):", preludes.len()); let show = std::cmp::min(16, preludes.len()); for p in preludes.iter().take(show) { eprintln!(" - {}", p); } if preludes.len() > show { eprintln!(" ... ({} more)", preludes.len() - show); } } process::exit(1); } }; // Merge preludes + main when enabled let ast = if use_ast && !prelude_asts.is_empty() { crate::runner::modes::common_util::resolve::merge_prelude_asts_with_main( prelude_asts, &main_ast, ) } else { main_ast }; // Macro expansion (env-gated) after merge let ast = crate::r#macro::maybe_expand_and_dump(&ast, false); let ast = crate::runner::modes::macro_child::normalize_core_pass(&ast); // Compile to MIR let mut mir_compiler = MirCompiler::new(); let compile_result = match crate::runner::modes::common_util::source_hint::compile_with_source_hint( &mut mir_compiler, ast, Some(filename), ) { Ok(result) => result, Err(e) => { eprintln!("❌ MIR compilation error: {}", e); process::exit(1); } }; println!("📊 MIR Module compiled successfully!"); println!("📊 Functions: {}", compile_result.module.functions.len()); // Inject method_id for BoxCall/PluginInvoke where resolvable (by-id path) #[allow(unused_mut)] let mut module = compile_result.module.clone(); let injected = inject_method_ids(&mut module); if injected > 0 { crate::cli_v!("[LLVM] method_id injected: {} places", injected); } // Phase 32 L-4.3a: JoinIR LLVM experiment hook // When NYASH_JOINIR_EXPERIMENT=1 and NYASH_JOINIR_LLVM_EXPERIMENT=1, // try to lower MIR → JoinIR → MIR' for Main.skip/1 to fix PHI issues. // JoinIR-converted functions are merged back into the original module. #[cfg(feature = "llvm-harness")] let module = if crate::config::env::joinir_experiment_enabled() && crate::config::env::joinir_llvm_experiment_enabled() && crate::config::env::llvm_use_harness() { use nyash_rust::mir::join_ir::lower_skip_ws_to_joinir; use nyash_rust::mir::join_ir_vm_bridge::convert_joinir_to_mir; eprintln!("[joinir/llvm] Attempting JoinIR path for LLVM execution"); // Try to lower Main.skip/1 to JoinIR if module.functions.contains_key("Main.skip/1") { match lower_skip_ws_to_joinir(&module) { Some(join_module) => { eprintln!( "[joinir/llvm] ✅ Lowered to JoinIR ({} functions)", join_module.functions.len() ); // Convert JoinIR back to MIR' (with normalized PHI) match convert_joinir_to_mir(&join_module) { Ok(mir_from_joinir) => { eprintln!( "[joinir/llvm] ✅ Converted to MIR' ({} functions)", mir_from_joinir.functions.len() ); // Merge JoinIR functions into original module // Strategy: Remove Main.skip/1 (PHI-problematic) and rename join_func_0 to Main.skip/1 let mut merged = module.clone(); // Remove the original PHI-problematic Main.skip/1 if merged.functions.remove("Main.skip/1").is_some() { eprintln!("[joinir/llvm] Removed original Main.skip/1 (PHI-problematic)"); } for (name, func) in mir_from_joinir.functions { // Rename join_func_0 → Main.skip/1 to maintain call compatibility let target_name = if name == "join_func_0" { eprintln!("[joinir/llvm] Renaming {} → Main.skip/1", name); "Main.skip/1".to_string() } else { eprintln!("[joinir/llvm] Adding JoinIR function: {}", name); name }; merged.functions.insert(target_name, func); } eprintln!( "[joinir/llvm] ✅ Merged module ({} functions)", merged.functions.len() ); merged } Err(e) => { eprintln!("[joinir/llvm] ❌ JoinIR→MIR conversion failed: {:?}", e); eprintln!("[joinir/llvm] Falling back to original MIR"); module } } } None => { eprintln!("[joinir/llvm] ❌ JoinIR lowering returned None"); eprintln!("[joinir/llvm] Falling back to original MIR"); module } } } else { eprintln!("[joinir/llvm] Main.skip/1 not found, using original MIR"); module } } else { module }; // Dev/Test helper: allow executing via PyVM harness when requested if std::env::var("SMOKES_USE_PYVM").ok().as_deref() == Some("1") { match super::common_util::pyvm::run_pyvm_harness_lib(&module, "llvm-ast") { Ok(code) => { std::process::exit(code); } Err(e) => { eprintln!("❌ PyVM harness error: {}", e); std::process::exit(1); } } } // If explicit object path is requested, emit object only if let Ok(_out_path) = std::env::var("NYASH_LLVM_OBJ_OUT") { #[cfg(feature = "llvm-harness")] { // Harness path (optional): if NYASH_LLVM_USE_HARNESS=1, try Python/llvmlite first. if crate::config::env::llvm_use_harness() { if let Err(e) = crate::runner::modes::common_util::exec::llvmlite_emit_object( &module, &_out_path, 20_000, ) { eprintln!("❌ {}", e); process::exit(1); } return; } // Verify object presence and size (>0) match std::fs::metadata(&_out_path) { Ok(meta) => { if meta.len() == 0 { eprintln!("❌ harness object is empty: {}", _out_path); process::exit(1); } if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { eprintln!( "[LLVM] object emitted: {} ({} bytes)", _out_path, meta.len() ); } } Err(e) => { eprintln!( "❌ harness output not found after emit: {} ({})", _out_path, e ); process::exit(1); } } return; } #[cfg(all(not(feature = "llvm-harness"), feature = "llvm-inkwell-legacy"))] { use nyash_rust::backend::llvm_compile_to_object; // Ensure parent directory exists for the object file if let Some(parent) = std::path::Path::new(&_out_path).parent() { let _ = std::fs::create_dir_all(parent); } crate::cli_v!( "[Runner/LLVM] emitting object to {} (cwd={})", _out_path, std::env::current_dir() .map(|p| p.display().to_string()) .unwrap_or_default() ); if let Err(e) = llvm_compile_to_object(&module, &_out_path) { eprintln!("❌ LLVM object emit error: {}", e); process::exit(1); } match std::fs::metadata(&_out_path) { Ok(meta) if meta.len() > 0 => { crate::cli_v!( "[LLVM] object emitted: {} ({} bytes)", _out_path, meta.len() ); } _ => { eprintln!("❌ LLVM object not found or empty: {}", _out_path); process::exit(1); } } return; } #[cfg(all(not(feature = "llvm-harness"), not(feature = "llvm-inkwell-legacy")))] { eprintln!("❌ LLVM backend not available (object emit)."); process::exit(1); } } // Execute via LLVM backend (harness preferred) #[cfg(feature = "llvm-harness")] { if crate::config::env::llvm_use_harness() { // Prefer producing a native executable via ny-llvmc, then execute it let exe_out = "tmp/nyash_llvm_run"; let libs = std::env::var("NYASH_LLVM_EXE_LIBS").ok(); match crate::runner::modes::common_util::exec::ny_llvmc_emit_exe_lib( &module, exe_out, None, libs.as_deref(), ) { Ok(()) => { match crate::runner::modes::common_util::exec::run_executable( exe_out, &[], 20_000, ) { Ok((code, _timed_out, stdout_text)) => { // Forward program stdout so parity tests can compare outputs if !stdout_text.is_empty() { print!("{}", stdout_text); } println!("✅ LLVM (harness) execution completed (exit={})", code); std::process::exit(code); } Err(e) => { eprintln!("❌ run executable error: {}", e); std::process::exit(1); } } } Err(e) => { eprintln!("❌ ny-llvmc emit-exe error: {}", e); eprintln!( " Hint: build ny-llvmc: cargo build -p nyash-llvm-compiler --release" ); std::process::exit(1); } } } } // Execute via LLVM backend (mock or real) #[cfg(feature = "llvm-inkwell-legacy")] { use nyash_rust::backend::llvm_compile_and_execute; let temp_path = "nyash_llvm_temp"; match llvm_compile_and_execute(&module, temp_path) { Ok(result) => { if let Some(int_result) = result.as_any().downcast_ref::() { let exit_code = int_result.value; println!("✅ LLVM execution completed!"); println!("📊 Exit code: {}", exit_code); process::exit(exit_code as i32); } else { println!("✅ LLVM execution completed (non-integer result)!"); println!("📊 Result: {}", result.to_string_box().value); } } Err(e) => { eprintln!("❌ LLVM execution error: {}", e); process::exit(1); } } } #[cfg(all(not(feature = "llvm-inkwell-legacy")))] { println!("🔧 Mock LLVM Backend Execution:"); println!(" Build with --features llvm-inkwell-legacy for Rust/inkwell backend, or set NYASH_LLVM_OBJ_OUT and NYASH_LLVM_USE_HARNESS=1 for harness."); // NamingBox SSOT: Select entry (arity-aware, Main.main → main fallback) let entry = crate::runner::modes::common_util::entry_selection::select_entry_function(&module); if let Some(main_func) = module.functions.get(&entry) { for (_bid, block) in &main_func.blocks { for inst in &block.instructions { match inst { MirInstruction::Return { value: Some(_) } => { println!("✅ Mock exit code: 42"); process::exit(42); } MirInstruction::Return { value: None } => { println!("✅ Mock exit code: 0"); process::exit(0); } _ => {} } } } } println!("✅ Mock exit code: 0"); process::exit(0); } } } // emit_mir_json_for_harness moved to crate::runner::mir_json_emit