Files
hakorune/src/runner.rs

1032 lines
44 KiB
Rust
Raw Normal View History

/*!
* Execution Runner Module - Nyash File and Mode Execution Coordinator
*
* This module handles all execution logic, backend selection, and mode coordination,
* separated from CLI parsing and the main entry point.
*/
use nyash_rust::cli::CliConfig;
use nyash_rust::{
box_trait::{NyashBox, StringBox, IntegerBox, BoolBox, VoidBox, AddBox, BoxCore},
tokenizer::{NyashTokenizer},
ast::ASTNode,
parser::NyashParser,
interpreter::NyashInterpreter,
mir::{MirCompiler, MirPrinter, MirInstruction},
backend::VM,
};
use nyash_rust::runtime::{NyashRuntime, NyashRuntimeBuilder};
use nyash_rust::box_factory::builtin::BuiltinGroups;
use nyash_rust::interpreter::SharedState;
use nyash_rust::box_factory::user_defined::UserDefinedBoxFactory;
use nyash_rust::core::model::BoxDeclaration as CoreBoxDecl;
use std::sync::Arc;
#[cfg(feature = "wasm-backend")]
use nyash_rust::backend::{wasm::WasmBackend, aot::AotBackend};
#[cfg(feature = "llvm")]
use nyash_rust::backend::{llvm_compile_and_execute};
use std::{fs, process};
mod modes;
// v2 plugin system imports
use nyash_rust::runtime;
use nyash_rust::runner_plugin_init;
/// Main execution coordinator
pub struct NyashRunner {
config: CliConfig,
}
impl NyashRunner {
/// Create a new runner with the given configuration
pub fn new(config: CliConfig) -> Self {
Self { config }
}
/// Run Nyash based on the configuration
pub fn run(&self) {
// 🏭 Phase 9.78b: Initialize unified registry
runtime::init_global_unified_registry();
// Try to initialize BID plugins from nyash.toml (best-effort)
// Allow disabling during snapshot/CI via NYASH_DISABLE_PLUGINS=1
if std::env::var("NYASH_DISABLE_PLUGINS").ok().as_deref() != Some("1") {
runner_plugin_init::init_bid_plugins();
}
// Optional: enable VM stats via CLI flags
if self.config.vm_stats {
std::env::set_var("NYASH_VM_STATS", "1");
}
if self.config.vm_stats_json {
// Prefer explicit JSON flag over any default
std::env::set_var("NYASH_VM_STATS_JSON", "1");
}
// Optional: JIT controls via CLI flags (centralized)
{
// CLI opt-in for JSONL events
if self.config.jit_events { std::env::set_var("NYASH_JIT_EVENTS", "1"); }
if self.config.jit_events_compile { std::env::set_var("NYASH_JIT_EVENTS_COMPILE", "1"); }
if self.config.jit_events_runtime { std::env::set_var("NYASH_JIT_EVENTS_RUNTIME", "1"); }
if let Some(ref p) = self.config.jit_events_path { std::env::set_var("NYASH_JIT_EVENTS_PATH", p); }
let mut jc = nyash_rust::jit::config::JitConfig::from_env();
jc.exec |= self.config.jit_exec;
jc.stats |= self.config.jit_stats;
jc.stats_json |= self.config.jit_stats_json;
jc.dump |= self.config.jit_dump;
if self.config.jit_threshold.is_some() { jc.threshold = self.config.jit_threshold; }
jc.phi_min |= self.config.jit_phi_min;
jc.hostcall |= self.config.jit_hostcall;
jc.handle_debug |= self.config.jit_handle_debug;
jc.native_f64 |= self.config.jit_native_f64;
jc.native_bool |= self.config.jit_native_bool;
// If observability is enabled and no threshold is provided, force threshold=1 so lowering runs and emits events
let events_on = std::env::var("NYASH_JIT_EVENTS").ok().as_deref() == Some("1")
|| std::env::var("NYASH_JIT_EVENTS_COMPILE").ok().as_deref() == Some("1")
|| std::env::var("NYASH_JIT_EVENTS_RUNTIME").ok().as_deref() == Some("1");
if events_on && jc.threshold.is_none() { jc.threshold = Some(1); }
if self.config.jit_only { std::env::set_var("NYASH_JIT_ONLY", "1"); }
// Apply runtime capability probe (e.g., disable b1 ABI if unsupported)
let caps = nyash_rust::jit::config::probe_capabilities();
jc = nyash_rust::jit::config::apply_runtime_caps(jc, caps);
// Optional DOT emit via CLI (ensures dump is on when path specified)
if let Some(path) = &self.config.emit_cfg {
std::env::set_var("NYASH_JIT_DOT", path);
jc.dump = true;
}
// Persist to env (CLI parity) and set as current
jc.apply_env();
nyash_rust::jit::config::set_current(jc.clone());
}
// Benchmark mode - can run without a file
if self.config.benchmark {
println!("📊 Nyash Performance Benchmark Suite");
println!("====================================");
println!("Running {} iterations per test...", self.config.iterations);
println!();
self.execute_benchmark_mode();
return;
}
if let Some(ref filename) = self.config.file {
// Independent JIT direct mode (no VM execute path)
if self.config.jit_direct {
self.run_file_jit_direct(filename);
return;
}
// Delegate file-mode execution to modes::common dispatcher
self.run_file(filename);
} else {
self.execute_demo_mode();
}
}
// init_bid_plugins moved to runner_plugin_init.rs
/// Execute file-based mode with backend selection
/// Execute demo mode with all demonstrations
fn execute_demo_mode(&self) {
println!("🦀 Nyash Rust Implementation - Everything is Box! 🦀");
println!("====================================================");
// Demonstrate basic Box creation and operations
demo_basic_boxes();
// Demonstrate Box operations
demo_box_operations();
// Demonstrate Box collections
demo_box_collections();
// Demonstrate Environment & Scope management
demo_environment_system();
// Demonstrate Tokenizer system
demo_tokenizer_system();
// Demonstrate Parser system
demo_parser_system();
// Demonstrate Interpreter system
demo_interpreter_system();
println!("\n🎉 All Box operations completed successfully!");
println!("Memory safety guaranteed by Rust's borrow checker! 🛡️");
}
/// Execute Nyash file with interpreter (moved to modes/common.rs)
#[cfg(any())]
fn execute_nyash_file(&self, filename: &str) {
// 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);
}
};
println!("📝 File contents:\n{}", code);
println!("\n🚀 Parsing and executing...\n");
// Test: immediate file creation (use relative path to avoid sandbox issues)
std::fs::create_dir_all("development/debug_hang_issue").ok();
std::fs::write("development/debug_hang_issue/test.txt", "START").ok();
// Parse the code with debug fuel limit
eprintln!("🔍 DEBUG: Starting parse with fuel: {:?}...", self.config.debug_fuel);
let ast = match NyashParser::parse_from_string_with_fuel(&code, self.config.debug_fuel) {
Ok(ast) => {
eprintln!("🔍 DEBUG: Parse completed, AST created");
ast
},
Err(e) => {
eprintln!("❌ Parse error: {}", e);
process::exit(1);
}
};
eprintln!("🔍 DEBUG: About to print parse success message...");
println!("✅ Parse successful!");
eprintln!("🔍 DEBUG: Parse success message printed");
// Debug log file write
if let Ok(mut file) = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open("development/debug_hang_issue/debug_trace.log")
{
use std::io::Write;
let _ = writeln!(file, "=== MAIN: Parse successful ===");
let _ = file.flush();
}
eprintln!("🔍 DEBUG: Creating interpreter...");
// Execute the AST
let mut interpreter = NyashInterpreter::new_with_groups(BuiltinGroups::native_full());
eprintln!("🔍 DEBUG: Starting execution...");
match interpreter.execute(ast) {
Ok(result) => {
println!("✅ Execution completed successfully!");
println!("Result: {}", result.to_string_box().value);
},
Err(e) => {
// Use enhanced error reporting with source context
eprintln!("❌ Runtime error:\n{}", e.detailed_message(Some(&code)));
process::exit(1);
}
}
}
/// Execute MIR compilation and processing mode (moved to modes/mir.rs)
#[cfg(any())]
fn execute_mir_mode(&self, filename: &str) {
// 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);
}
};
// Parse to AST
let ast = match NyashParser::parse_from_string(&code) {
Ok(ast) => ast,
Err(e) => {
eprintln!("❌ Parse error: {}", e);
process::exit(1);
}
};
// Compile to MIR (opt passes configurable)
let mut mir_compiler = MirCompiler::with_options(!self.config.no_optimize);
let compile_result = match mir_compiler.compile(ast) {
Ok(result) => result,
Err(e) => {
eprintln!("❌ MIR compilation error: {}", e);
process::exit(1);
}
};
// Verify MIR if requested
if self.config.verify_mir {
println!("🔍 Verifying MIR...");
match &compile_result.verification_result {
Ok(()) => println!("✅ MIR verification passed!"),
Err(errors) => {
eprintln!("❌ MIR verification failed:");
for error in errors {
eprintln!("{}", error);
}
process::exit(1);
}
}
}
// Dump MIR if requested
if self.config.dump_mir {
let mut printer = if self.config.mir_verbose { MirPrinter::verbose() } else { MirPrinter::new() };
if self.config.mir_verbose_effects { printer.set_show_effects_inline(true); }
println!("🚀 MIR Output for {}:", filename);
println!("{}", printer.print_module(&compile_result.module));
}
}
/// Execute VM mode (moved to modes/vm.rs)
#[cfg(any())]
fn execute_vm_mode(&self, filename: &str) {
// 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);
}
};
// Parse to AST
let ast = match NyashParser::parse_from_string(&code) {
Ok(ast) => ast,
Err(e) => {
eprintln!("❌ Parse error: {}", e);
process::exit(1);
}
};
// Prepare runtime and collect Box declarations for VM user-defined types
let runtime = {
let rt = NyashRuntimeBuilder::new()
.with_builtin_groups(BuiltinGroups::native_full())
.build();
self.collect_box_declarations(&ast, &rt);
// Register UserDefinedBoxFactory backed by the same declarations
let mut shared = SharedState::new();
shared.box_declarations = rt.box_declarations.clone();
let udf = Arc::new(UserDefinedBoxFactory::new(shared));
if let Ok(mut reg) = rt.box_registry.lock() {
reg.register(udf);
}
rt
};
// Compile to MIR (opt passes configurable)
let mut mir_compiler = MirCompiler::with_options(!self.config.no_optimize);
let compile_result = match mir_compiler.compile(ast) {
Ok(result) => result,
Err(e) => {
eprintln!("❌ MIR compilation error: {}", e);
process::exit(1);
}
};
// Execute with VM using prepared runtime
let mut vm = VM::with_runtime(runtime);
match vm.execute_module(&compile_result.module) {
Ok(result) => {
println!("✅ VM execution completed successfully!");
if let Some(func) = compile_result.module.functions.get("main") {
use nyash_rust::mir::MirType;
use nyash_rust::box_trait::{NyashBox, IntegerBox, BoolBox, StringBox};
use nyash_rust::boxes::FloatBox;
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!("❌ VM execution error: {}", e);
process::exit(1);
}
}
}
/// Collect Box declarations (moved to modes/vm.rs)
#[cfg(any())]
fn collect_box_declarations(&self, ast: &ASTNode, runtime: &NyashRuntime) {
fn walk(node: &ASTNode, runtime: &NyashRuntime) {
match node {
ASTNode::Program { statements, .. } => {
for st in statements { walk(st, runtime); }
}
feat: Implement field visibility (public/private) system ## Major Features Added ### Field Visibility System - Added `private { ... }` and `public { ... }` blocks in box declarations - Default visibility is now handled explicitly (fields must be in either block) - Visibility checks enforced at both interpreter and VM levels ### Parser Enhancements - Extended AST with public_fields and private_fields vectors - Added parsing for visibility blocks in box definitions - Maintained backward compatibility with existing `init { ... }` syntax ### Interpreter Implementation - Added visibility checks in field access (get_field/set_field) - External access to private fields now throws appropriate errors - Internal access (within methods) always allowed ### VM Implementation - Extended VM with object_class tracking for visibility checks - RefGet/RefSet instructions now enforce field visibility - Fixed nested box declaration collection (boxes defined inside methods) ### Test Examples Added - docs/examples/visibility_ok.nyash - demonstrates correct usage - docs/examples/visibility_error.nyash - tests private field access errors ## Technical Details ### Error Messages - Interpreter: "Field 'X' is private in Y" - VM: Same error message for consistency ### Current Limitations - All RefGet/RefSet treated as external access in VM (internal flag future work) - Legacy `init { ... }` fields treated as having unspecified visibility ## Test Results ✅ Interpreter: Both test cases pass correctly ✅ VM: Both test cases pass correctly after nested declaration fix This implements the foundation for proper encapsulation in Nyash, following the "explicit is better than implicit" philosophy. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-21 03:08:13 +09:00
ASTNode::FunctionDeclaration { body, .. } => {
// Walk into function bodies to find nested box declarations
for st in body { walk(st, runtime); }
}
ASTNode::BoxDeclaration { name, fields, public_fields, private_fields, methods, constructors, init_fields, weak_fields, is_interface, extends, implements, type_parameters, .. } => {
// Walk into methods/constructors to find nested box declarations
for (_mname, mnode) in methods {
walk(mnode, runtime);
}
for (_ckey, cnode) in constructors {
walk(cnode, runtime);
}
let decl = CoreBoxDecl {
name: name.clone(),
fields: fields.clone(),
feat: Implement field visibility (public/private) system ## Major Features Added ### Field Visibility System - Added `private { ... }` and `public { ... }` blocks in box declarations - Default visibility is now handled explicitly (fields must be in either block) - Visibility checks enforced at both interpreter and VM levels ### Parser Enhancements - Extended AST with public_fields and private_fields vectors - Added parsing for visibility blocks in box definitions - Maintained backward compatibility with existing `init { ... }` syntax ### Interpreter Implementation - Added visibility checks in field access (get_field/set_field) - External access to private fields now throws appropriate errors - Internal access (within methods) always allowed ### VM Implementation - Extended VM with object_class tracking for visibility checks - RefGet/RefSet instructions now enforce field visibility - Fixed nested box declaration collection (boxes defined inside methods) ### Test Examples Added - docs/examples/visibility_ok.nyash - demonstrates correct usage - docs/examples/visibility_error.nyash - tests private field access errors ## Technical Details ### Error Messages - Interpreter: "Field 'X' is private in Y" - VM: Same error message for consistency ### Current Limitations - All RefGet/RefSet treated as external access in VM (internal flag future work) - Legacy `init { ... }` fields treated as having unspecified visibility ## Test Results ✅ Interpreter: Both test cases pass correctly ✅ VM: Both test cases pass correctly after nested declaration fix This implements the foundation for proper encapsulation in Nyash, following the "explicit is better than implicit" philosophy. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-21 03:08:13 +09:00
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(),
};
if let Ok(mut map) = runtime.box_declarations.write() {
map.insert(name.clone(), decl);
}
}
_ => {}
}
}
walk(ast, runtime);
}
// execute_wasm_mode moved to runner::modes::wasm
// execute_aot_mode moved to runner::modes::aot
/// Execute LLVM mode (moved to modes/llvm.rs)
#[cfg(any())]
fn execute_llvm_mode(&self, filename: &str) {
// 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);
}
};
// Parse to AST
let ast = match NyashParser::parse_from_string(&code) {
Ok(ast) => ast,
Err(e) => {
eprintln!("❌ Parse error: {}", e);
process::exit(1);
}
};
// Compile to MIR
let mut mir_compiler = MirCompiler::new();
let compile_result = match mir_compiler.compile(ast) {
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());
// Execute via LLVM backend (mock implementation)
#[cfg(feature = "llvm")]
{
let temp_path = "nyash_llvm_temp";
match llvm_compile_and_execute(&compile_result.module, temp_path) {
Ok(result) => {
if let Some(int_result) = result.as_any().downcast_ref::<IntegerBox>() {
let exit_code = int_result.value;
println!("✅ LLVM execution completed!");
println!("📊 Exit code: {}", exit_code);
// Exit with the same code for testing
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(not(feature = "llvm"))]
{
// Mock implementation for demonstration
println!("🔧 Mock LLVM Backend Execution:");
println!(" This demonstrates the LLVM backend integration structure.");
println!(" For actual LLVM compilation, build with --features llvm");
println!(" and ensure LLVM 17+ development libraries are installed.");
// Analyze the MIR to provide a meaningful mock result
if let Some(main_func) = compile_result.module.functions.get("Main.main") {
for (_block_id, block) in &main_func.blocks {
for inst in &block.instructions {
match inst {
MirInstruction::Return { value: Some(_) } => {
println!(" 📊 Found return instruction - would generate LLVM return 42");
println!("✅ Mock LLVM execution completed!");
println!("📊 Mock exit code: 42");
process::exit(42);
}
MirInstruction::Return { value: None } => {
println!(" 📊 Found void return - would generate LLVM return 0");
println!("✅ Mock LLVM execution completed!");
println!("📊 Mock exit code: 0");
process::exit(0);
}
_ => {}
}
}
}
}
println!("✅ Mock LLVM execution completed!");
println!("📊 Mock exit code: 0");
process::exit(0);
}
}
/// Execute benchmark mode (moved to modes/bench.rs)
#[cfg(any())]
fn execute_benchmark_mode(&self) {
println!("🏁 Running benchmark mode with {} iterations", self.config.iterations);
// Simple benchmark test file
let test_code = r#"
local x
x = 42
local y
y = x + 58
return y
"#;
println!("\n🧪 Test code:");
println!("{}", test_code);
// Benchmark interpreter
println!("\n⚡ Interpreter Backend:");
let start = std::time::Instant::now();
for _ in 0..self.config.iterations {
if let Ok(ast) = NyashParser::parse_from_string(test_code) {
let mut interpreter = NyashInterpreter::new_with_groups(BuiltinGroups::native_full());
let _ = interpreter.execute(ast);
}
}
let interpreter_time = start.elapsed();
println!(" {} iterations in {:?} ({:.2} ops/sec)",
self.config.iterations, interpreter_time,
self.config.iterations as f64 / interpreter_time.as_secs_f64());
// Benchmark VM if available
println!("\n🚀 VM Backend:");
let start = std::time::Instant::now();
for _ in 0..self.config.iterations {
if let Ok(ast) = NyashParser::parse_from_string(test_code) {
let mut mir_compiler = MirCompiler::new();
if let Ok(compile_result) = mir_compiler.compile(ast) {
let mut vm = VM::new();
let _ = vm.execute_module(&compile_result.module);
}
}
}
let vm_time = start.elapsed();
println!(" {} iterations in {:?} ({:.2} ops/sec)",
self.config.iterations, vm_time,
self.config.iterations as f64 / vm_time.as_secs_f64());
// Performance comparison
let speedup = interpreter_time.as_secs_f64() / vm_time.as_secs_f64();
println!("\n📊 Performance Summary:");
println!(" VM is {:.2}x {} than Interpreter",
if speedup > 1.0 { speedup } else { 1.0 / speedup },
if speedup > 1.0 { "faster" } else { "slower" });
}
}
impl NyashRunner {
/// Run a file through independent JIT engine (no VM execute loop)
fn run_file_jit_direct(&self, filename: &str) {
use std::fs;
use nyash_rust::{parser::NyashParser, mir::MirCompiler};
// Small helper for unified error output (text or JSON)
let emit_err = |phase: &str, code: &str, msg: &str| {
if std::env::var("NYASH_JIT_STATS_JSON").ok().as_deref() == Some("1")
|| std::env::var("NYASH_JIT_ERROR_JSON").ok().as_deref() == Some("1") {
let payload = serde_json::json!({
"kind": "jit_direct_error",
"phase": phase,
"code": code,
"message": msg,
"file": filename,
});
println!("{}", payload.to_string());
} else {
eprintln!("[JIT-direct][{}][{}] {}", phase, code, msg);
}
};
// Require cranelift feature at runtime by attempting compile; if unavailable compile_function returns None
let code = match fs::read_to_string(filename) {
Ok(s) => s,
Err(e) => { emit_err("read_file", "IO", &format!("{}", e)); std::process::exit(1); }
};
let ast = match NyashParser::parse_from_string(&code) {
Ok(a) => a, Err(e) => { emit_err("parse", "SYNTAX", &format!("{}", e)); std::process::exit(1); }
};
let mut mc = MirCompiler::new();
let cr = match mc.compile(ast) { Ok(m) => m, Err(e) => { emit_err("mir", "MIR_COMPILE", &format!("{}", e)); std::process::exit(1); } };
let func = match cr.module.functions.get("main") { Some(f) => f, None => { emit_err("mir", "NO_MAIN", "No main function found"); std::process::exit(1); } };
// Guard: refuse write-effects in jit-direct when policy.read_only
{
use nyash_rust::mir::MirInstruction;
use nyash_rust::mir::effect::Effect;
let policy = nyash_rust::jit::policy::current();
let mut writes = 0usize;
for (_bbid, bb) in func.blocks.iter() {
for inst in bb.instructions.iter() {
let mask = inst.effects();
if mask.contains(Effect::WriteHeap) {
writes += 1;
}
}
if let Some(term) = &bb.terminator {
if term.effects().contains(Effect::WriteHeap) { writes += 1; }
}
}
if policy.read_only && writes > 0 {
emit_err("policy", "WRITE_EFFECTS", &format!("write-effects detected ({} ops). jit-direct is read-only at this stage.", writes));
std::process::exit(1);
}
}
let mut engine = nyash_rust::jit::engine::JitEngine::new();
match engine.compile_function("main", func) {
Some(h) => {
// Optional event: compile
nyash_rust::jit::events::emit("compile", &func.signature.name, Some(h), None, serde_json::json!({}));
// Parse JIT args from env: NYASH_JIT_ARGS (comma-separated), with optional type prefixes
// Formats per arg: i:123, f:3.14, b:true/false, h:42 (handle), or bare numbers (int), true/false (bool)
let mut jit_args: Vec<nyash_rust::jit::abi::JitValue> = Vec::new();
if let Ok(s) = std::env::var("NYASH_JIT_ARGS") {
for raw in s.split(',') {
let t = raw.trim();
if t.is_empty() { continue; }
let v = if let Some(rest) = t.strip_prefix("i:") {
rest.parse::<i64>().ok().map(nyash_rust::jit::abi::JitValue::I64)
} else if let Some(rest) = t.strip_prefix("f:") {
rest.parse::<f64>().ok().map(nyash_rust::jit::abi::JitValue::F64)
} else if let Some(rest) = t.strip_prefix("b:") {
let b = matches!(rest, "1"|"true"|"True"|"TRUE");
Some(nyash_rust::jit::abi::JitValue::Bool(b))
} else if let Some(rest) = t.strip_prefix("h:") {
rest.parse::<u64>().ok().map(nyash_rust::jit::abi::JitValue::Handle)
} else if t.eq_ignore_ascii_case("true") || t == "1" { Some(nyash_rust::jit::abi::JitValue::Bool(true)) }
else if t.eq_ignore_ascii_case("false") || t == "0" { Some(nyash_rust::jit::abi::JitValue::Bool(false)) }
else if let Ok(iv) = t.parse::<i64>() { Some(nyash_rust::jit::abi::JitValue::I64(iv)) }
else if let Ok(fv) = t.parse::<f64>() { Some(nyash_rust::jit::abi::JitValue::F64(fv)) }
else { None };
if let Some(jv) = v { jit_args.push(jv); }
}
}
// Coerce args to expected MIR types
use nyash_rust::mir::MirType;
let expected = &func.signature.params;
if expected.len() != jit_args.len() {
emit_err("args", "COUNT_MISMATCH", &format!("expected={}, passed={}", expected.len(), jit_args.len()));
eprintln!("Hint: set NYASH_JIT_ARGS as comma-separated values, e.g., i:42,f:3.14,b:true");
std::process::exit(1);
}
let mut coerced: Vec<nyash_rust::jit::abi::JitValue> = Vec::with_capacity(jit_args.len());
for (i, (exp, got)) in expected.iter().zip(jit_args.iter()).enumerate() {
let cv = match exp {
MirType::Integer => match got {
nyash_rust::jit::abi::JitValue::I64(v) => nyash_rust::jit::abi::JitValue::I64(*v),
nyash_rust::jit::abi::JitValue::F64(f) => nyash_rust::jit::abi::JitValue::I64(*f as i64),
nyash_rust::jit::abi::JitValue::Bool(b) => nyash_rust::jit::abi::JitValue::I64(if *b {1} else {0}),
_ => { emit_err("args", "TYPE_MISMATCH", &format!("param#{} expects Integer", i)); std::process::exit(1); }
},
MirType::Float => match got {
nyash_rust::jit::abi::JitValue::F64(f) => nyash_rust::jit::abi::JitValue::F64(*f),
nyash_rust::jit::abi::JitValue::I64(v) => nyash_rust::jit::abi::JitValue::F64(*v as f64),
nyash_rust::jit::abi::JitValue::Bool(b) => nyash_rust::jit::abi::JitValue::F64(if *b {1.0} else {0.0}),
_ => { emit_err("args", "TYPE_MISMATCH", &format!("param#{} expects Float", i)); std::process::exit(1); }
},
MirType::Bool => match got {
nyash_rust::jit::abi::JitValue::Bool(b) => nyash_rust::jit::abi::JitValue::Bool(*b),
nyash_rust::jit::abi::JitValue::I64(v) => nyash_rust::jit::abi::JitValue::Bool(*v != 0),
nyash_rust::jit::abi::JitValue::F64(f) => nyash_rust::jit::abi::JitValue::Bool(*f != 0.0),
_ => { emit_err("args", "TYPE_MISMATCH", &format!("param#{} expects Bool", i)); std::process::exit(1); }
},
MirType::String | MirType::Box(_) | MirType::Array(_) | MirType::Future(_) => match got {
nyash_rust::jit::abi::JitValue::Handle(h) => nyash_rust::jit::abi::JitValue::Handle(*h),
_ => { emit_err("args", "TYPE_MISMATCH", &format!("param#{} expects handle (h:<id>)", i)); std::process::exit(1); }
},
MirType::Void | MirType::Unknown => {
// Keep as-is
*got
}
};
coerced.push(cv);
}
nyash_rust::jit::rt::set_current_jit_args(&coerced);
let t0 = std::time::Instant::now();
let out = engine.execute_handle(h, &coerced);
match out {
Some(v) => {
let ms = t0.elapsed().as_millis();
nyash_rust::jit::events::emit("execute", &func.signature.name, Some(h), Some(ms), serde_json::json!({}));
// Normalize result according to MIR return type for friendly output
use nyash_rust::mir::MirType;
let ret_ty = &func.signature.return_type;
let vmv = match (ret_ty, v) {
(MirType::Bool, nyash_rust::jit::abi::JitValue::I64(i)) => nyash_rust::backend::vm::VMValue::Bool(i != 0),
(MirType::Bool, nyash_rust::jit::abi::JitValue::Bool(b)) => nyash_rust::backend::vm::VMValue::Bool(b),
(MirType::Float, nyash_rust::jit::abi::JitValue::F64(f)) => nyash_rust::backend::vm::VMValue::Float(f),
(MirType::Float, nyash_rust::jit::abi::JitValue::I64(i)) => nyash_rust::backend::vm::VMValue::Float(i as f64),
// Default adapter for other combos
_ => nyash_rust::jit::abi::adapter::from_jit_value(v),
};
println!("✅ JIT-direct execution completed successfully!");
// Pretty print with expected type tag
let (ety, sval) = match (ret_ty, &vmv) {
(MirType::Bool, nyash_rust::backend::vm::VMValue::Bool(b)) => ("Bool", b.to_string()),
(MirType::Float, nyash_rust::backend::vm::VMValue::Float(f)) => ("Float", format!("{}", f)),
(MirType::Integer, nyash_rust::backend::vm::VMValue::Integer(i)) => ("Integer", i.to_string()),
// Fallbacks
(_, nyash_rust::backend::vm::VMValue::Integer(i)) => ("Integer", i.to_string()),
(_, nyash_rust::backend::vm::VMValue::Float(f)) => ("Float", format!("{}", f)),
(_, nyash_rust::backend::vm::VMValue::Bool(b)) => ("Bool", b.to_string()),
(_, nyash_rust::backend::vm::VMValue::String(s)) => ("String", s.clone()),
(_, nyash_rust::backend::vm::VMValue::BoxRef(arc)) => ("BoxRef", arc.type_name().to_string()),
(_, nyash_rust::backend::vm::VMValue::Future(_)) => ("Future", "<future>".to_string()),
(_, nyash_rust::backend::vm::VMValue::Void) => ("Void", "void".to_string()),
};
println!("ResultType(MIR): {}", ety);
println!("Result: {}", sval);
// Optional JSON stats
if std::env::var("NYASH_JIT_STATS_JSON").ok().as_deref() == Some("1") {
let cfg = nyash_rust::jit::config::current();
let caps = nyash_rust::jit::config::probe_capabilities();
let (phi_t, phi_b1, ret_b) = engine.last_lower_stats();
let abi_mode = if cfg.native_bool_abi && caps.supports_b1_sig { "b1_bool" } else { "i64_bool" };
let payload = serde_json::json!({
"version": 1,
"function": func.signature.name,
"abi_mode": abi_mode,
"abi_b1_enabled": cfg.native_bool_abi,
"abi_b1_supported": caps.supports_b1_sig,
"b1_norm_count": nyash_rust::jit::rt::b1_norm_get(),
"ret_bool_hint_count": nyash_rust::jit::rt::ret_bool_hint_get(),
"phi_total_slots": phi_t,
"phi_b1_slots": phi_b1,
"ret_bool_hint_used": ret_b,
});
println!("{}", payload.to_string());
}
}
None => {
nyash_rust::jit::events::emit("fallback", &func.signature.name, Some(h), None, serde_json::json!({"reason":"trap_or_missing"}));
emit_err("execute", "TRAP_OR_MISSING", "execution failed (trap or missing handle)");
std::process::exit(1);
}
}
}
None => {
emit_err("compile", "UNAVAILABLE", "Build with --features cranelift-jit");
std::process::exit(1);
}
}
}
}
// Demo functions (moved from main.rs)
fn demo_basic_boxes() {
println!("\n📦 1. Basic Box Creation:");
// Create different types of boxes
let string_box = StringBox::new("Hello, Nyash!".to_string());
let int_box = IntegerBox::new(42);
let bool_box = BoolBox::new(true);
let void_box = VoidBox::new();
println!(" StringBox: {}", string_box.to_string_box().value);
println!(" IntegerBox: {}", int_box.to_string_box().value);
println!(" BoolBox: {}", bool_box.to_string_box().value);
println!(" VoidBox: {}", void_box.to_string_box().value);
// Show unique IDs
println!(" Box IDs: String={}, Integer={}, Bool={}, Void={}",
string_box.box_id(), int_box.box_id(), bool_box.box_id(), void_box.box_id());
}
fn demo_box_operations() {
println!("\n🔄 2. Box Operations:");
// Addition between boxes
let left = IntegerBox::new(10);
let right = IntegerBox::new(32);
let add_box = AddBox::new(Box::new(left), Box::new(right));
println!(" 10 + 32 = {}", add_box.to_string_box().value);
// String concatenation
let str1 = StringBox::new("Hello, ".to_string());
let str2 = StringBox::new("World!".to_string());
let concat_box = AddBox::new(Box::new(str1), Box::new(str2));
println!(" \"Hello, \" + \"World!\" = {}", concat_box.to_string_box().value);
}
fn demo_box_collections() {
println!("\n📚 3. Box Collections:");
// This would be expanded when ArrayBox is implemented
println!(" Box collections functionality placeholder");
println!(" (ArrayBox and other collection types will be demonstrated here)");
}
fn demo_environment_system() {
println!("\n🌍 4. Environment & Scope Management:");
println!(" Environment demo placeholder - full testing done in interpreter");
}
fn demo_tokenizer_system() {
println!("\n🔤 5. Tokenizer System:");
// Test code to tokenize
let test_code = "x = 42 + y";
println!(" Input: {}", test_code);
// Tokenize the code
let mut tokenizer = NyashTokenizer::new(test_code);
match tokenizer.tokenize() {
Ok(tokens) => {
println!(" Tokenized {} tokens successfully", tokens.len());
},
Err(e) => println!(" Tokenization error: {}", e),
}
}
fn demo_parser_system() {
println!("\n🌳 6. Parser & AST System:");
// Test simple box declaration
println!(" 📝 Simple Box Declaration Test:");
let simple_code = r#"
box TestBox {
value
getValue() {
return this.value
}
}
"#;
match NyashParser::parse_from_string(simple_code) {
Ok(ast) => {
println!(" Input: {}", simple_code.trim());
println!(" AST: {}", ast);
if let ASTNode::Program { statements, .. } = &ast {
println!(" Program has {} statements", statements.len());
for (i, stmt) in statements.iter().enumerate() {
println!(" [{}] {}", i, stmt.info());
}
}
}
Err(e) => println!(" Error: {}", e),
}
// Test assignment and method call
println!("\n 🚀 Assignment & Method Call Test:");
let assignment_code = r#"
obj = new TestBox()
obj.value = "test123"
print("Direct field: " + obj.value)
print("Method call: " + obj.getValue())
"#;
match NyashParser::parse_from_string(assignment_code) {
Ok(ast) => {
println!(" Successfully parsed assignment & method call code");
if let ASTNode::Program { statements, .. } = &ast {
println!(" Parsed {} statements:", statements.len());
for (i, stmt) in statements.iter().enumerate() {
println!(" [{}] {} ({})", i, stmt.info(), stmt.node_type());
}
}
}
Err(e) => println!(" Error: {}", e),
}
// Test expression parsing
println!("\n ⚡ Expression Parsing Test:");
let expr_code = r#"
result = x + y * z
condition = a == b && c < d
"#;
match NyashParser::parse_from_string(expr_code) {
Ok(ast) => {
println!(" Successfully parsed complex expressions");
if let ASTNode::Program { statements, .. } = &ast {
for (i, stmt) in statements.iter().enumerate() {
if let ASTNode::Assignment { target, value, .. } = stmt {
println!(" Assignment [{}]: {} = {}", i, target.info(), value.info());
}
}
}
}
Err(e) => println!(" Error: {}", e),
}
// Test control structures
println!("\n 🔄 Control Structure Test:");
let control_code = r#"
if condition {
print("True branch")
} else {
print("False branch")
}
loop {
print("Loop body")
return
}
"#;
match NyashParser::parse_from_string(control_code) {
Ok(ast) => {
println!(" Successfully parsed control structures");
if let ASTNode::Program { statements, .. } = &ast {
for (i, stmt) in statements.iter().enumerate() {
println!(" [{}] {} ({})", i, stmt.info(), stmt.node_type());
}
}
}
Err(e) => println!(" Error: {}", e),
}
}
fn demo_interpreter_system() {
println!("\n🎭 7. Interpreter System:");
// Simple execution test
let simple_code = r#"
local x
x = 42
return x
"#;
println!(" 📝 Simple Variable Test:");
println!(" Code: {}", simple_code.trim());
match NyashParser::parse_from_string(simple_code) {
Ok(ast) => {
let mut interpreter = NyashInterpreter::new_with_groups(BuiltinGroups::native_full());
match interpreter.execute(ast) {
Ok(result) => {
println!(" ✅ Result: {}", result.to_string_box().value);
},
Err(e) => {
println!(" ❌ Execution error: {}", e);
}
}
}
Err(e) => println!(" ❌ Parse error: {}", e),
}
// Expression evaluation test
let expr_code = r#"
local result
result = 10 + 32
return result
"#;
println!("\n ⚡ Expression Evaluation Test:");
println!(" Code: {}", expr_code.trim());
match NyashParser::parse_from_string(expr_code) {
Ok(ast) => {
let mut interpreter = NyashInterpreter::new_with_groups(BuiltinGroups::native_full());
match interpreter.execute(ast) {
Ok(result) => {
println!(" ✅ Result: {}", result.to_string_box().value);
},
Err(e) => {
println!(" ❌ Execution error: {}", e);
}
}
}
Err(e) => println!(" ❌ Parse error: {}", e),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_runner_creation() {
let config = CliConfig {
file: None,
debug_fuel: Some(100000),
dump_ast: false,
dump_mir: false,
verify_mir: false,
mir_verbose: false,
mir_verbose_effects: false,
no_optimize: false,
backend: "interpreter".to_string(),
compile_wasm: false,
compile_native: false,
output_file: None,
benchmark: false,
iterations: 10,
vm_stats: false,
vm_stats_json: false,
};
let runner = NyashRunner::new(config);
assert_eq!(runner.config.backend, "interpreter");
}
}