Files
hakorune/src/runner/dispatch.rs

331 lines
14 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*!
* Runner dispatch helpers — execute MIR module and report result
*/
use super::*;
use crate::runner::json_v0_bridge;
use nyash_rust::parser::NyashParser;
use std::{fs, process};
/// Thin file dispatcher: select backend and delegate to mode executors
pub(crate) fn execute_file_with_backend(runner: &NyashRunner, filename: &str) {
// Selfhost pipeline (Ny -> JSON v0)
// Default: ON. Backwardcompat envs:
// - NYASH_USE_NY_COMPILER={1|true|on} to force ON
// - NYASH_USE_NY_COMPILER={0|false|off} or NYASH_DISABLE_NY_COMPILER/HAKO_DISABLE_NY_COMPILER to disable
let mut use_selfhost = true;
if let Ok(v) = std::env::var("NYASH_USE_NY_COMPILER") {
let lv = v.trim().to_ascii_lowercase();
use_selfhost = matches!(lv.as_str(), "1" | "true" | "on");
}
let disabled = std::env::var("NYASH_DISABLE_NY_COMPILER")
.ok()
.map(|v| {
let lv = v.trim().to_ascii_lowercase();
matches!(lv.as_str(), "1" | "true" | "on")
})
.unwrap_or(false)
|| std::env::var("HAKO_DISABLE_NY_COMPILER")
.ok()
.map(|v| {
let lv = v.trim().to_ascii_lowercase();
matches!(lv.as_str(), "1" | "true" | "on")
})
.unwrap_or(false);
if use_selfhost && !disabled {
if runner.try_run_selfhost_pipeline(filename) {
return;
} else {
crate::cli_v!("[ny-compiler] fallback to default path (MVP unavailable for this input)");
}
}
// Direct v0 bridge when requested via CLI/env
let groups = runner.config.as_groups();
let use_ny_parser = groups.parser.parser_ny
|| std::env::var("NYASH_USE_NY_PARSER").ok().as_deref() == Some("1");
if use_ny_parser {
let code = match fs::read_to_string(filename) {
Ok(content) => content,
Err(e) => {
eprintln!("❌ Error reading file {}: {}", filename, e);
process::exit(1);
}
};
match json_v0_bridge::parse_source_v0_to_module(&code) {
Ok(module) => {
crate::cli_v!("🚀 Nyash MIR Interpreter - (parser=ny) Executing file: {} 🚀", filename);
runner.execute_mir_module(&module);
return;
}
Err(e) => {
eprintln!("❌ Direct bridge parse error in {}: {}", filename, e);
process::exit(1);
}
}
}
// AST dump mode
if groups.debug.dump_ast {
println!("🧠 Nyash AST Dump - Processing file: {}", filename);
let code = match fs::read_to_string(filename) {
Ok(content) => content,
Err(e) => {
eprintln!("❌ Error reading file {}: {}", filename, e);
process::exit(1);
}
};
let ast = match NyashParser::parse_from_string(&code) {
Ok(ast) => ast,
Err(e) => {
eprintln!("❌ Parse error in {}: {}", filename, e);
process::exit(1);
}
};
// Optional macro expansion dump (no-op expansion for now)
let ast2 = if crate::r#macro::enabled() {
let a = crate::r#macro::maybe_expand_and_dump(&ast, true);
crate::runner::modes::macro_child::normalize_core_pass(&a)
} else {
ast.clone()
};
println!("{:#?}", ast2);
return;
}
// Dump expanded AST as JSON v0 and exit
if runner.config.dump_expanded_ast_json {
let code = match fs::read_to_string(filename) {
Ok(content) => content,
Err(e) => { eprintln!("❌ Error reading file {}: {}", filename, e); process::exit(1); }
};
let ast = match NyashParser::parse_from_string(&code) {
Ok(ast) => ast,
Err(e) => { eprintln!("❌ Parse error in {}: {}", filename, e); process::exit(1); }
};
let expanded = if crate::r#macro::enabled() {
let a = crate::r#macro::maybe_expand_and_dump(&ast, false);
crate::runner::modes::macro_child::normalize_core_pass(&a)
} else { ast };
let j = crate::r#macro::ast_json::ast_to_json(&expanded);
println!("{}", j.to_string());
return;
}
// MIR dump/verify
if groups.debug.dump_mir || groups.debug.verify_mir {
crate::cli_v!("🚀 Nyash MIR Compiler - Processing file: {} 🚀", filename);
runner.execute_mir_mode(filename);
return;
}
// WASM / AOT (feature-gated)
if groups.compile_wasm {
#[cfg(feature = "wasm-backend")]
{
super::modes::wasm::execute_wasm_mode(runner, filename);
return;
}
#[cfg(not(feature = "wasm-backend"))]
{
eprintln!("❌ WASM backend not available. Please rebuild with: cargo build --features wasm-backend");
process::exit(1);
}
}
if groups.compile_native {
#[cfg(feature = "cranelift-jit")]
{
runner.execute_aot_mode(filename);
return;
}
#[cfg(not(feature = "cranelift-jit"))]
{
eprintln!("❌ Native AOT compilation requires Cranelift. Please rebuild: cargo build --features cranelift-jit");
process::exit(1);
}
}
// Backend selection
match groups.backend.backend.as_str() {
"mir" => {
crate::cli_v!("🚀 Nyash MIR Interpreter - Executing file: {} 🚀", filename);
runner.execute_mir_mode(filename);
}
"vm" => {
crate::cli_v!("🚀 Nyash VM Backend - Executing file: {} 🚀", filename);
// Prefer lightweight in-crate MIR interpreter as VM fallback
runner.execute_vm_fallback_interpreter(filename);
}
#[cfg(feature = "cranelift-jit")]
"jit-direct" => {
crate::cli_v!("⚡ Nyash JIT-Direct Backend - Executing file: {} ⚡", filename);
#[cfg(feature = "cranelift-jit")]
{
// Use independent JIT-direct runner method (no VM execute loop)
runner.run_file_jit_direct(filename);
}
#[cfg(not(feature = "cranelift-jit"))]
{
eprintln!("❌ Cranelift backend not available. Please rebuild with: cargo build --features cranelift-jit");
process::exit(1);
}
}
"llvm" => {
crate::cli_v!("⚡ Nyash LLVM Backend - Executing file: {} ⚡", filename);
runner.execute_llvm_mode(filename);
}
other => {
eprintln!("❌ Unknown backend: {}. Use 'vm' or 'llvm'.", other);
std::process::exit(2);
}
}
}
impl NyashRunner {
/// Execute a MIR module quietly and return an OS exit code derived from the
/// program's return value (Integer/Bool/Float). Strings and other values map to 0.
/// - Integer: value as i64, truncated to 0..=255 (two's complement wrap)
/// - Bool: true=1, false=0
/// - Float: floor toward zero (as i64), truncated to 0..=255
pub(crate) fn execute_mir_module_quiet_exit(&self, module: &crate::mir::MirModule) -> i32 {
use crate::backend::MirInterpreter;
use crate::box_trait::{BoolBox, IntegerBox, StringBox};
use crate::boxes::FloatBox;
use crate::mir::MirType;
fn to_rc(val: i64) -> i32 {
let m = ((val % 256) + 256) % 256; // normalize into 0..=255
m as i32
}
let mut interp = MirInterpreter::new();
match interp.execute_module(module) {
Ok(result) => {
if let Some(func) = module.functions.get("main") {
match &func.signature.return_type {
MirType::Integer => {
if let Some(ib) = result.as_any().downcast_ref::<IntegerBox>() {
return to_rc(ib.value);
}
}
MirType::Bool => {
if let Some(bb) = result.as_any().downcast_ref::<BoolBox>() {
return if bb.value { 1 } else { 0 };
}
}
MirType::Float => {
if let Some(fb) = result.as_any().downcast_ref::<FloatBox>() {
return to_rc(fb.value as i64);
}
if let Some(ib) = result.as_any().downcast_ref::<IntegerBox>() {
return to_rc(ib.value);
}
}
_ => {}
}
// Fallbacks by inspecting boxed value kinds (robust to imprecise return types)
if let Some(ib) = result.as_any().downcast_ref::<IntegerBox>() {
return to_rc(ib.value);
}
if let Some(bb) = result.as_any().downcast_ref::<BoolBox>() {
return if bb.value { 1 } else { 0 };
}
if let Some(fb) = result.as_any().downcast_ref::<FloatBox>() {
return to_rc(fb.value as i64);
}
if let Some(_sb) = result.as_any().downcast_ref::<StringBox>() {
return 0; // strings do not define rc semantics yet
}
0
} else {
0
}
}
Err(_) => 1,
}
}
pub(crate) fn execute_mir_module(&self, module: &crate::mir::MirModule) {
// If CLI requested MIR JSON emit, write to file and exit immediately.
let groups = self.config.as_groups();
if let Some(path) = groups.emit.emit_mir_json.as_ref() {
let p = std::path::Path::new(path);
if let Err(e) = crate::runner::mir_json_emit::emit_mir_json_for_harness_bin(module, p) {
eprintln!("❌ MIR JSON emit error: {}", e);
std::process::exit(1);
}
println!("MIR JSON written: {}", p.display());
std::process::exit(0);
}
// If CLI requested EXE emit, generate JSON then invoke ny-llvmc to link NyRT and exit.
if let Some(exe_out) = groups.emit.emit_exe.as_ref() {
if let Err(e) = crate::runner::modes::common_util::exec::ny_llvmc_emit_exe_bin(
module,
exe_out,
groups.emit.emit_exe_nyrt.as_deref(),
groups.emit.emit_exe_libs.as_deref(),
) {
eprintln!("{}", e);
std::process::exit(1);
}
println!("EXE written: {}", exe_out);
std::process::exit(0);
}
use crate::backend::MirInterpreter;
use crate::box_trait::{BoolBox, IntegerBox, StringBox};
use crate::boxes::FloatBox;
use crate::mir::MirType;
let mut interp = MirInterpreter::new();
match interp.execute_module(module) {
Ok(result) => {
println!("✅ MIR interpreter execution completed!");
if let Some(func) = module.functions.get("main") {
let (ety, sval) = match &func.signature.return_type {
MirType::Float => {
if let Some(fb) = result.as_any().downcast_ref::<FloatBox>() {
("Float", format!("{}", fb.value))
} else if let Some(ib) = result.as_any().downcast_ref::<IntegerBox>() {
("Float", format!("{}", ib.value as f64))
} else {
("Float", result.to_string_box().value)
}
}
MirType::Integer => {
if let Some(ib) = result.as_any().downcast_ref::<IntegerBox>() {
("Integer", ib.value.to_string())
} else {
("Integer", result.to_string_box().value)
}
}
MirType::Bool => {
if let Some(bb) = result.as_any().downcast_ref::<BoolBox>() {
("Bool", bb.value.to_string())
} else if let Some(ib) = result.as_any().downcast_ref::<IntegerBox>() {
("Bool", (ib.value != 0).to_string())
} else {
("Bool", result.to_string_box().value)
}
}
MirType::String => {
if let Some(sb) = result.as_any().downcast_ref::<StringBox>() {
("String", sb.value.clone())
} else {
("String", result.to_string_box().value)
}
}
_ => (result.type_name(), result.to_string_box().value),
};
println!("ResultType(MIR): {}", ety);
println!("Result: {}", sval);
} else {
println!("Result: {:?}", result);
}
}
Err(e) => {
eprintln!("❌ MIR interpreter error: {}", e);
std::process::exit(1);
}
}
}
}