diff --git a/CLAUDE.md b/CLAUDE.md index 64134d8c..255ec7ae 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -518,6 +518,11 @@ codex exec "質問内容" llvmliteベースのLLVMバックエンド実装。箱理論により650行→100行の簡略化を実現! Rust/inkwellの複雑さを回避して、シンプルに2000行程度でMIR14→LLVM変換を実現。 +⚠️ **重要**: **JIT/Craneliftは現在まともに動作しません!** +- ビルドは可能(`cargo build --release --features cranelift-jit`) +- 実行は不可(内部実装が未完成) +- **Python LLVMルートとPyVMのみが現在の開発対象です** + #### 実行方法 ```bash cd src/llvm_py diff --git a/src/backend/llvm/compiler/codegen/mod.rs b/src/backend/llvm/compiler/codegen/mod.rs index dad91d91..112ad12f 100644 --- a/src/backend/llvm/compiler/codegen/mod.rs +++ b/src/backend/llvm/compiler/codegen/mod.rs @@ -1,3 +1,12 @@ +//! LLVM Codegen Orchestrator +//! +//! Structure +//! - `function.rs`: per-function lowering (MIR → LLVM IR) +//! - `utils.rs`: helpers like `sanitize_symbol` and const-string maps +//! - `instructions/*`: focused lowerers and terminators (branch/jump/return, calls, boxcall, externcall) +//! - `types.rs`: MIR→LLVM type mapping and classifiers +//! +//! Keep this file slim: predeclare functions, delegate lowering, emit entry wrapper/object. use super::helpers::{as_float, as_int, map_type}; use super::LLVMCompiler; use crate::backend::llvm::context::CodegenContext; @@ -1115,7 +1124,6 @@ impl LLVMCompiler { } } } -Old duplicate lowering block removed */ #[cfg(test)] @@ -1128,3 +1136,160 @@ mod tests { assert!(compiler.is_ok()); } } +//! LLVM Codegen Orchestrator +//! +//! Structure +//! - `function.rs`: per-function lowering (MIR → LLVM IR) +//! - `utils.rs`: helpers like `sanitize_symbol` +//! - `instructions/*`: focused lowerers and terminators (branch/jump/return, calls, boxcall, externcall) +//! - `types.rs`: MIR→LLVM type mapping and classifiers +//! +//! Keep this file slim: predeclare functions, delegate lowering, emit entry wrapper/object. + +use super::helpers::map_type; +use super::LLVMCompiler; +use crate::backend::llvm::context::CodegenContext; +use crate::mir::function::MirModule; +use inkwell::context::Context; +use inkwell::{ + types::BasicTypeEnum, + values::{BasicValueEnum, FunctionValue}, +}; +use std::collections::HashMap; + +// Submodules +mod types; +mod instructions; +mod utils; +mod function; + +// Local helpers (thin wrappers) +fn sanitize_symbol(name: &str) -> String { utils::sanitize_symbol(name) } + +fn emit_wrapper_and_object<'ctx>( + codegen: &CodegenContext<'ctx>, + entry_name: &str, + output_path: &str, +) -> Result<(), String> { + let i64t = codegen.context.i64_type(); + let ny_main_ty = i64t.fn_type(&[], false); + let ny_main = codegen.module.add_function("ny_main", ny_main_ty, None); + let entry_bb = codegen.context.append_basic_block(ny_main, "entry"); + codegen.builder.position_at_end(entry_bb); + let entry_sym = format!("ny_f_{}", sanitize_symbol(&entry_name)); + let entry_fn = codegen + .module + .get_function(&entry_sym) + .ok_or_else(|| format!("entry function symbol not found: {}", entry_sym))?; + let call = codegen.builder.build_call(entry_fn, &[], "call_main").map_err(|e| e.to_string())?; + let rv = call.try_as_basic_value().left(); + let ret_v = if let Some(v) = rv { + match v { + BasicValueEnum::IntValue(iv) => { + if iv.get_type().get_bit_width() == 64 { iv } else { codegen.builder.build_int_z_extend(iv, i64t, "ret_zext").map_err(|e| e.to_string())? } + } + BasicValueEnum::PointerValue(pv) => codegen.builder.build_ptr_to_int(pv, i64t, "ret_p2i").map_err(|e| e.to_string())?, + BasicValueEnum::FloatValue(fv) => codegen.builder.build_float_to_signed_int(fv, i64t, "ret_f2i").map_err(|e| e.to_string())?, + _ => i64t.const_zero(), + } + } else { i64t.const_zero() }; + codegen.builder.build_return(Some(&ret_v)).map_err(|e| e.to_string())?; + if !ny_main.verify(true) { return Err("ny_main verification failed".to_string()); } + let verbose = std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1"); + if verbose { eprintln!("[LLVM] emitting object to {} (begin)", output_path); } + match codegen.target_machine.write_to_file(&codegen.module, inkwell::targets::FileType::Object, std::path::Path::new(output_path)) { + Ok(_) => { + if std::fs::metadata(output_path).is_err() { + let buf = codegen.target_machine.write_to_memory_buffer(&codegen.module, inkwell::targets::FileType::Object).map_err(|e| format!("Failed to get object buffer: {}", e))?; + std::fs::write(output_path, buf.as_slice()).map_err(|e| format!("Failed to write object to '{}': {}", output_path, e))?; + if verbose { eprintln!("[LLVM] wrote object via memory buffer fallback: {} ({} bytes)", output_path, buf.get_size()); } + } else if verbose { + if let Ok(meta) = std::fs::metadata(output_path) { eprintln!("[LLVM] wrote object via file API: {} ({} bytes)", output_path, meta.len()); } + } + if verbose { eprintln!("[LLVM] emit complete (Ok branch) for {}", output_path); } + Ok(()) + } + Err(e) => { + let buf = codegen.target_machine.write_to_memory_buffer(&codegen.module, inkwell::targets::FileType::Object).map_err(|ee| format!("Failed to write object ({}); and memory buffer failed: {}", e, ee))?; + std::fs::write(output_path, buf.as_slice()).map_err(|ee| format!("Failed to write object to '{}': {} (original error: {})", output_path, ee, e))?; + if verbose { eprintln!("[LLVM] wrote object via error fallback: {} ({} bytes)", output_path, buf.get_size()); eprintln!("[LLVM] emit complete (Err branch handled) for {}", output_path); } + Ok(()) + } + } +} + +impl LLVMCompiler { + pub fn new() -> Result { + Ok(Self { values: HashMap::new() }) + } + + pub fn compile_module(&self, mir_module: &MirModule, output_path: &str) -> Result<(), String> { + if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { + eprintln!( + "[LLVM] compile_module start: functions={}, out={}", + mir_module.functions.len(), + output_path + ); + } + let context = Context::create(); + let codegen = CodegenContext::new(&context, "nyash_module")?; + let box_type_ids = crate::backend::llvm::box_types::load_box_type_ids(); + + // Find entry function + let (entry_name, _entry_func_ref) = if let Some((n, f)) = mir_module + .functions + .iter() + .find(|(_n, f)| f.metadata.is_entry_point) + { + (n.clone(), f) + } else if let Some(f) = mir_module.functions.get("Main.main") { + ("Main.main".to_string(), f) + } else if let Some(f) = mir_module.functions.get("main") { + ("main".to_string(), f) + } else if let Some((n, f)) = mir_module.functions.iter().next() { + (n.clone(), f) + } else { + return Err("Main.main function not found in module".to_string()); + }; + + // Predeclare all MIR functions as LLVM functions + let mut llvm_funcs: HashMap = HashMap::new(); + for (name, f) in &mir_module.functions { + let ret_bt = match f.signature.return_type { + crate::mir::MirType::Void => codegen.context.i64_type().into(), + ref t => map_type(codegen.context, t)?, + }; + let mut params_bt: Vec = Vec::new(); + for pt in &f.signature.params { params_bt.push(map_type(codegen.context, pt)?); } + let param_vals: Vec<_> = params_bt.iter().map(|t| (*t).into()).collect(); + let ll_fn_ty = match ret_bt { + BasicTypeEnum::IntType(t) => t.fn_type(¶m_vals, false), + BasicTypeEnum::FloatType(t) => t.fn_type(¶m_vals, false), + BasicTypeEnum::PointerType(t) => t.fn_type(¶m_vals, false), + _ => return Err("Unsupported return basic type".to_string()), + }; + let sym = format!("ny_f_{}", utils::sanitize_symbol(name)); + let lf = codegen.module.add_function(&sym, ll_fn_ty, None); + llvm_funcs.insert(name.clone(), lf); + } + + // Lower all functions + for (name, func) in &mir_module.functions { + let llvm_func = *llvm_funcs.get(name).ok_or("predecl not found")?; + function::lower_one_function(&codegen, llvm_func, func, name, &box_type_ids, &llvm_funcs)?; + } + + // Build entry wrapper and emit object + emit_wrapper_and_object(&codegen, &entry_name, output_path) + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_compiler_creation() { + let compiler = LLVMCompiler::new(); + assert!(compiler.is_ok()); + } +} diff --git a/src/boxes/future/mod.rs b/src/boxes/future/mod.rs index 4a406025..e300c829 100644 --- a/src/boxes/future/mod.rs +++ b/src/boxes/future/mod.rs @@ -28,7 +28,7 @@ struct Inner { /// Used for non-owning registries (TaskGroup/implicit group) to avoid leaks. #[derive(Clone, Debug)] pub struct FutureWeak { - pub(crate) inner: Weak, + inner: Weak, } impl Clone for NyashFutureBox { diff --git a/src/interpreter/core.rs b/src/interpreter/core.rs index e767795c..105ac30a 100644 --- a/src/interpreter/core.rs +++ b/src/interpreter/core.rs @@ -31,6 +31,7 @@ pub(crate) fn debug_log(msg: &str) { } // Conditional debug macro - unified with utils::debug_on() +#[allow(unused_macros)] macro_rules! debug_trace { ($($arg:tt)*) => { if crate::interpreter::utils::debug_on() { eprintln!($($arg)*); } diff --git a/src/interpreter/eval.rs b/src/interpreter/eval.rs index bf2d8af5..910ef146 100644 --- a/src/interpreter/eval.rs +++ b/src/interpreter/eval.rs @@ -1,7 +1,7 @@ //! Evaluation entry points: execute program and nodes use crate::ast::ASTNode; -use crate::box_trait::{NyashBox, VoidBox, StringBox}; +use crate::box_trait::{NyashBox, VoidBox}; use super::{NyashInterpreter, RuntimeError, ControlFlow}; impl NyashInterpreter { diff --git a/src/interpreter/expressions/mod.rs b/src/interpreter/expressions/mod.rs index 037ee84c..0190eb44 100644 --- a/src/interpreter/expressions/mod.rs +++ b/src/interpreter/expressions/mod.rs @@ -22,7 +22,7 @@ use std::sync::Arc; impl NyashInterpreter { /// Build closure environment by capturing 'me' and free variables by value (P1) fn build_closure_env(&mut self, params: &Vec, body: &Vec) -> Result { - use std::collections::{HashSet, VecDeque}; + use std::collections::HashSet; let mut env = crate::boxes::function_box::ClosureEnv::new(); // Capture 'me' if bound if let Ok(mev) = self.resolve_variable("me") { env.me_value = Some(Arc::downgrade(&mev)); } diff --git a/src/interpreter/methods/p2p_methods.rs b/src/interpreter/methods/p2p_methods.rs index 290b4e78..baa4392f 100644 --- a/src/interpreter/methods/p2p_methods.rs +++ b/src/interpreter/methods/p2p_methods.rs @@ -8,7 +8,6 @@ use crate::interpreter::RuntimeError; use crate::ast::ASTNode; use crate::box_trait::{NyashBox, StringBox}; use crate::boxes::{IntentBox, P2PBox}; -use crate::box_trait::BoolBox; impl NyashInterpreter { /// IntentBoxのメソッド実行 (RwLock版) diff --git a/src/interpreter/methods/system_methods.rs b/src/interpreter/methods/system_methods.rs index c5ac9622..d5692bdf 100644 --- a/src/interpreter/methods/system_methods.rs +++ b/src/interpreter/methods/system_methods.rs @@ -7,7 +7,7 @@ */ use crate::ast::ASTNode; -use crate::box_trait::{NyashBox, VoidBox, StringBox, BoolBox}; +use crate::box_trait::{NyashBox, BoolBox}; use crate::boxes::gc_config_box::GcConfigBox; use crate::boxes::debug_config_box::DebugConfigBox; use crate::interpreter::{NyashInterpreter, RuntimeError}; @@ -168,4 +168,4 @@ impl NyashInterpreter { }), } } -} \ No newline at end of file +} diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 761d50ef..fd5809d5 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -19,7 +19,6 @@ use crate::boxes::debug_box::DebugBox; // WASM-specific Box types (conditionally included) #[cfg(target_arch = "wasm32")] use crate::boxes::web::{WebDisplayBox, WebConsoleBox, WebCanvasBox}; -use crate::finalization; use crate::exception_box; use std::collections::HashMap; diff --git a/src/mir/builder.rs b/src/mir/builder.rs index 17d1b826..4e3eb771 100644 --- a/src/mir/builder.rs +++ b/src/mir/builder.rs @@ -5,13 +5,12 @@ */ use super::{ - MirInstruction, BasicBlock, BasicBlockId, MirFunction, MirModule, - FunctionSignature, ValueId, ConstValue, BinaryOp, UnaryOp, CompareOp, + MirInstruction, BasicBlock, BasicBlockId, MirFunction, MirModule, + FunctionSignature, ValueId, ConstValue, CompareOp, MirType, EffectMask, Effect, BasicBlockIdGenerator, ValueIdGenerator }; -use super::slot_registry::{get_or_assign_type_id, reserve_method_slot}; use super::slot_registry::resolve_slot_by_type_name; -use crate::ast::{ASTNode, LiteralValue, BinaryOperator}; +use crate::ast::{ASTNode, LiteralValue}; use std::collections::HashMap; use std::collections::HashSet; use std::fs; @@ -30,6 +29,7 @@ mod exprs_lambda; // lambda lowering mod exprs_include; // include lowering mod plugin_sigs; // plugin signature loader mod vars; // variables/scope helpers +pub(crate) mod loops; // small loop helpers (header/exit context) // moved helpers to builder/utils.rs @@ -90,62 +90,6 @@ pub struct MirBuilder { } impl MirBuilder { - /// Emit a Box method call (unified: BoxCall) - fn emit_box_or_plugin_call( - &mut self, - dst: Option, - box_val: ValueId, - method: String, - method_id: Option, - args: Vec, - effects: EffectMask, - ) -> Result<(), String> { - // Emit instruction first - self.emit_instruction(MirInstruction::BoxCall { dst, box_val, method: method.clone(), method_id, args, effects })?; - // Heuristic return type inference for common builtin box methods - if let Some(d) = dst { - // Try to infer receiver box type from NewBox origin; fallback to current value_types - let mut recv_box: Option = self.value_origin_newbox.get(&box_val).cloned(); - if recv_box.is_none() { - if let Some(t) = self.value_types.get(&box_val) { - match t { - super::MirType::String => recv_box = Some("StringBox".to_string()), - super::MirType::Box(name) => recv_box = Some(name.clone()), - _ => {} - } - } - } - if let Some(bt) = recv_box { - if let Some(mt) = self.plugin_method_sigs.get(&(bt.clone(), method.clone())) { - self.value_types.insert(d, mt.clone()); - } else { - let inferred: Option = match (bt.as_str(), method.as_str()) { - // Built-in box methods - ("StringBox", "length") | ("StringBox", "len") => Some(super::MirType::Integer), - ("StringBox", "is_empty") => Some(super::MirType::Bool), - ("StringBox", "charCodeAt") => Some(super::MirType::Integer), - // String-producing methods (important for LLVM ret handling) - ("StringBox", "substring") - | ("StringBox", "concat") - | ("StringBox", "replace") - | ("StringBox", "trim") - | ("StringBox", "toUpper") - | ("StringBox", "toLower") => Some(super::MirType::String), - ("ArrayBox", "length") => Some(super::MirType::Integer), - // Core MapBox minimal inference (core-first) - ("MapBox", "size") => Some(super::MirType::Integer), - ("MapBox", "has") => Some(super::MirType::Bool), - ("MapBox", "get") => Some(super::MirType::Box("Any".to_string())), - _ => None, - }; - if let Some(mt) = inferred { - self.value_types.insert(d, mt); - } - } - } - } - Ok(()) - } /// Create a new MIR builder pub fn new() -> Self { let plugin_method_sigs = plugin_sigs::load_plugin_method_sigs(); @@ -171,57 +115,6 @@ impl MirBuilder { } } - /// Emit a type check instruction (Unified: TypeOp(Check)) - #[allow(dead_code)] - pub(super) fn emit_type_check(&mut self, value: ValueId, expected_type: String) -> Result { - let dst = self.value_gen.next(); - self.emit_instruction(MirInstruction::TypeOp { dst, op: super::TypeOpKind::Check, value, ty: super::MirType::Box(expected_type) })?; - Ok(dst) - } - - /// Emit a cast instruction (Unified: TypeOp(Cast)) - #[allow(dead_code)] - pub(super) fn emit_cast(&mut self, value: ValueId, target_type: super::MirType) -> Result { - let dst = self.value_gen.next(); - self.emit_instruction(MirInstruction::TypeOp { dst, op: super::TypeOpKind::Cast, value, ty: target_type.clone() })?; - Ok(dst) - } - - /// Emit a weak reference creation (Unified: WeakRef(New)) - #[allow(dead_code)] - pub(super) fn emit_weak_new(&mut self, box_val: ValueId) -> Result { - if crate::config::env::mir_core13_pure() { - // Pure mode: avoid WeakRef emission; pass-through - return Ok(box_val); - } - let dst = self.value_gen.next(); - self.emit_instruction(MirInstruction::WeakRef { dst, op: super::WeakRefOp::New, value: box_val })?; - Ok(dst) - } - - /// Emit a weak reference load (Unified: WeakRef(Load)) - #[allow(dead_code)] - pub(super) fn emit_weak_load(&mut self, weak_ref: ValueId) -> Result { - if crate::config::env::mir_core13_pure() { - // Pure mode: avoid WeakRef emission; pass-through - return Ok(weak_ref); - } - let dst = self.value_gen.next(); - self.emit_instruction(MirInstruction::WeakRef { dst, op: super::WeakRefOp::Load, value: weak_ref })?; - Ok(dst) - } - - /// Emit a barrier read (Unified: Barrier(Read)) - #[allow(dead_code)] - pub(super) fn emit_barrier_read(&mut self, ptr: ValueId) -> Result<(), String> { - self.emit_instruction(MirInstruction::Barrier { op: super::BarrierOp::Read, ptr }) - } - - /// Emit a barrier write (Unified: Barrier(Write)) - #[allow(dead_code)] - pub(super) fn emit_barrier_write(&mut self, ptr: ValueId) -> Result<(), String> { - self.emit_instruction(MirInstruction::Barrier { op: super::BarrierOp::Write, ptr }) - } // moved to builder_calls.rs: lower_method_as_function diff --git a/src/mir/builder/decls.rs b/src/mir/builder/decls.rs index 9b19c073..70e7d523 100644 --- a/src/mir/builder/decls.rs +++ b/src/mir/builder/decls.rs @@ -1,5 +1,5 @@ // Declarations lowering: static boxes and box declarations -use super::{MirInstruction, ConstValue, ValueId, BasicBlockId}; +use super::{MirInstruction, ConstValue, ValueId}; use crate::ast::ASTNode; use std::collections::HashSet; use crate::mir::slot_registry::{get_or_assign_type_id, reserve_method_slot}; diff --git a/src/mir/builder/exprs.rs b/src/mir/builder/exprs.rs index 0f5b6249..a5fe4ab1 100644 --- a/src/mir/builder/exprs.rs +++ b/src/mir/builder/exprs.rs @@ -1,6 +1,6 @@ // Expression lowering split from builder.rs to keep files lean -use super::{MirInstruction, ConstValue, BasicBlockId, ValueId}; -use crate::ast::{ASTNode, LiteralValue}; +use super::{MirInstruction, ConstValue, ValueId}; +use crate::ast::ASTNode; impl super::MirBuilder { // Main expression dispatcher diff --git a/src/mir/builder/loops.rs b/src/mir/builder/loops.rs new file mode 100644 index 00000000..677e7257 --- /dev/null +++ b/src/mir/builder/loops.rs @@ -0,0 +1,24 @@ +//! Small loop utilities for MirBuilder +use super::{BasicBlockId}; + +/// Push loop context (header/exit) onto the MirBuilder stacks. +pub(crate) fn push_loop_context(builder: &mut super::MirBuilder, header: BasicBlockId, exit: BasicBlockId) { + builder.loop_header_stack.push(header); + builder.loop_exit_stack.push(exit); +} + +/// Pop loop context (header/exit) from the MirBuilder stacks. +pub(crate) fn pop_loop_context(builder: &mut super::MirBuilder) { + let _ = builder.loop_header_stack.pop(); + let _ = builder.loop_exit_stack.pop(); +} + +/// Peek current loop header block id +pub(crate) fn current_header(builder: &super::MirBuilder) -> Option { + builder.loop_header_stack.last().copied() +} + +/// Peek current loop exit block id +pub(crate) fn current_exit(builder: &super::MirBuilder) -> Option { + builder.loop_exit_stack.last().copied() +} diff --git a/src/mir/builder/utils.rs b/src/mir/builder/utils.rs index 39676745..1a47dffb 100644 --- a/src/mir/builder/utils.rs +++ b/src/mir/builder/utils.rs @@ -1,5 +1,6 @@ use std::fs; use super::{BasicBlock, BasicBlockId}; +use crate::mir::{TypeOpKind, WeakRefOp, BarrierOp}; // Resolve include path using nyash.toml include.roots if present pub(super) fn resolve_include_path_builder(filename: &str) -> String { @@ -69,3 +70,86 @@ impl super::MirBuilder { } } } + +// Call/Type/WeakRef emission helpers (moved from builder.rs) +impl super::MirBuilder { + /// Emit a Box method call or plugin call (unified BoxCall) + pub(super) fn emit_box_or_plugin_call( + &mut self, + dst: Option, + box_val: super::ValueId, + method: String, + method_id: Option, + args: Vec, + effects: super::EffectMask, + ) -> Result<(), String> { + self.emit_instruction(super::MirInstruction::BoxCall { dst, box_val, method: method.clone(), method_id, args, effects })?; + if let Some(d) = dst { + let mut recv_box: Option = self.value_origin_newbox.get(&box_val).cloned(); + if recv_box.is_none() { + if let Some(t) = self.value_types.get(&box_val) { + match t { super::MirType::String => recv_box = Some("StringBox".to_string()), super::MirType::Box(name) => recv_box = Some(name.clone()), _ => {} } + } + } + if let Some(bt) = recv_box { + if let Some(mt) = self.plugin_method_sigs.get(&(bt.clone(), method.clone())) { + self.value_types.insert(d, mt.clone()); + } else { + let inferred: Option = match (bt.as_str(), method.as_str()) { + ("StringBox", "length") | ("StringBox", "len") => Some(super::MirType::Integer), + ("StringBox", "is_empty") => Some(super::MirType::Bool), + ("StringBox", "charCodeAt") => Some(super::MirType::Integer), + ("StringBox", "substring") | ("StringBox", "concat") | ("StringBox", "replace") | ("StringBox", "trim") | ("StringBox", "toUpper") | ("StringBox", "toLower") => Some(super::MirType::String), + ("ArrayBox", "length") => Some(super::MirType::Integer), + ("MapBox", "size") => Some(super::MirType::Integer), + ("MapBox", "has") => Some(super::MirType::Bool), + ("MapBox", "get") => Some(super::MirType::Box("Any".to_string())), + _ => None, + }; + if let Some(mt) = inferred { self.value_types.insert(d, mt); } + } + } + } + Ok(()) + } + + #[allow(dead_code)] + pub(super) fn emit_type_check(&mut self, value: super::ValueId, expected_type: String) -> Result { + let dst = self.value_gen.next(); + self.emit_instruction(super::MirInstruction::TypeOp { dst, op: TypeOpKind::Check, value, ty: super::MirType::Box(expected_type) })?; + Ok(dst) + } + + #[allow(dead_code)] + pub(super) fn emit_cast(&mut self, value: super::ValueId, target_type: super::MirType) -> Result { + let dst = self.value_gen.next(); + self.emit_instruction(super::MirInstruction::TypeOp { dst, op: TypeOpKind::Cast, value, ty: target_type.clone() })?; + Ok(dst) + } + + #[allow(dead_code)] + pub(super) fn emit_weak_new(&mut self, box_val: super::ValueId) -> Result { + if crate::config::env::mir_core13_pure() { return Ok(box_val); } + let dst = self.value_gen.next(); + self.emit_instruction(super::MirInstruction::WeakRef { dst, op: WeakRefOp::New, value: box_val })?; + Ok(dst) + } + + #[allow(dead_code)] + pub(super) fn emit_weak_load(&mut self, weak_ref: super::ValueId) -> Result { + if crate::config::env::mir_core13_pure() { return Ok(weak_ref); } + let dst = self.value_gen.next(); + self.emit_instruction(super::MirInstruction::WeakRef { dst, op: WeakRefOp::Load, value: weak_ref })?; + Ok(dst) + } + + #[allow(dead_code)] + pub(super) fn emit_barrier_read(&mut self, ptr: super::ValueId) -> Result<(), String> { + self.emit_instruction(super::MirInstruction::Barrier { op: BarrierOp::Read, ptr }) + } + + #[allow(dead_code)] + pub(super) fn emit_barrier_write(&mut self, ptr: super::ValueId) -> Result<(), String> { + self.emit_instruction(super::MirInstruction::Barrier { op: BarrierOp::Write, ptr }) + } +} diff --git a/src/mir/loop_builder.rs b/src/mir/loop_builder.rs index 8b9fcb08..c63b73ec 100644 --- a/src/mir/loop_builder.rs +++ b/src/mir/loop_builder.rs @@ -67,9 +67,8 @@ impl<'a> LoopBuilder<'a> { let after_loop_id = self.new_block(); self.loop_header = Some(header_id); self.continue_snapshots.clear(); - self.parent_builder.loop_exit_stack.push(after_loop_id); // Push loop context to parent builder (for nested break/continue lowering) - self.parent_builder.loop_header_stack.push(header_id); + crate::mir::builder::loops::push_loop_context(self.parent_builder, header_id, after_loop_id); // 2. Preheader -> Header へのジャンプ self.emit_jump(header_id)?; @@ -119,9 +118,7 @@ impl<'a> LoopBuilder<'a> { // 10. ループ後の処理 self.set_current_block(after_loop_id)?; // Pop loop context - let _ = self.parent_builder.loop_header_stack.pop(); - // loop exit stack mirrors header stack; maintain symmetry - let _ = self.parent_builder.loop_exit_stack.pop(); + crate::mir::builder::loops::pop_loop_context(self.parent_builder); // void値を返す let void_dst = self.new_value(); @@ -386,12 +383,12 @@ impl<'a> LoopBuilder<'a> { // Jump to loop exit (after_loop_id) if available let cur_block = self.current_block()?; // Ensure parent has recorded current loop exit; if not, record now - if self.parent_builder.loop_exit_stack.last().copied().is_none() { + if crate::mir::builder::loops::current_exit(self.parent_builder).is_none() { // Determine after_loop by peeking the next id used earlier: // In this builder, after_loop_id was created above; record it for nested lowering // We approximate by using the next block id minus 1 (after_loop) which we set below before branch } - if let Some(exit_bb) = self.parent_builder.loop_exit_stack.last().copied() { + if let Some(exit_bb) = crate::mir::builder::loops::current_exit(self.parent_builder) { self.emit_jump(exit_bb)?; let _ = self.add_predecessor(exit_bb, cur_block); } diff --git a/src/mir/passes/method_id_inject.rs b/src/mir/passes/method_id_inject.rs index 150967e9..4b5a3f35 100644 --- a/src/mir/passes/method_id_inject.rs +++ b/src/mir/passes/method_id_inject.rs @@ -45,7 +45,7 @@ pub fn inject_method_ids(module: &mut MirModule) -> usize { let mid_u16 = if let Some(h) = host_guard.as_ref() { // Try resolve via plugin config (may fail for builtins) match h.resolve_method(&bt, method) { - Ok(mh) => Some((mh.method_id as u16)), + Ok(mh) => Some(mh.method_id as u16), Err(_) => resolve_slot_by_type_name(&bt, method), } } else { @@ -63,7 +63,7 @@ pub fn inject_method_ids(module: &mut MirModule) -> usize { // Resolve id as above let mid_u16 = if let Some(h) = host_guard.as_ref() { match h.resolve_method(&bt, method) { - Ok(mh) => Some((mh.method_id as u16)), + Ok(mh) => Some(mh.method_id as u16), Err(_) => resolve_slot_by_type_name(&bt, method), } } else { @@ -91,4 +91,3 @@ pub fn inject_method_ids(module: &mut MirModule) -> usize { injected } - diff --git a/src/runner/dispatch.rs b/src/runner/dispatch.rs index a63de075..91fafdcd 100644 --- a/src/runner/dispatch.rs +++ b/src/runner/dispatch.rs @@ -7,12 +7,11 @@ use crate::runner::json_v0_bridge; use nyash_rust::parser::NyashParser; use std::{fs, process}; -impl NyashRunner { - /// Thin file dispatcher: select backend and delegate to mode executors - pub(crate) fn run_file(&self, filename: &str) { +/// 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) behind env gate if std::env::var("NYASH_USE_NY_COMPILER").ok().as_deref() == Some("1") { - if self.try_run_selfhost_pipeline(filename) { + if runner.try_run_selfhost_pipeline(filename) { return; } else if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { eprintln!("[ny-compiler] fallback to default path (MVP unavailable for this input)"); @@ -20,7 +19,7 @@ impl NyashRunner { } // Direct v0 bridge when requested via CLI/env - let use_ny_parser = self.config.parser_ny || std::env::var("NYASH_USE_NY_PARSER").ok().as_deref() == Some("1"); + let use_ny_parser = runner.config.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, @@ -31,7 +30,7 @@ impl NyashRunner { if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { println!("🚀 Nyash MIR Interpreter - (parser=ny) Executing file: {} 🚀", filename); } - self.execute_mir_module(&module); + runner.execute_mir_module(&module); return; } Err(e) => { eprintln!("❌ Direct bridge parse error: {}", e); process::exit(1); } @@ -39,7 +38,7 @@ impl NyashRunner { } // AST dump mode - if self.config.dump_ast { + if runner.config.dump_ast { println!("🧠 Nyash AST Dump - Processing file: {}", filename); let code = match fs::read_to_string(filename) { Ok(content) => content, @@ -54,35 +53,39 @@ impl NyashRunner { } // MIR dump/verify - if self.config.dump_mir || self.config.verify_mir { + if runner.config.dump_mir || runner.config.verify_mir { if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { println!("🚀 Nyash MIR Compiler - Processing file: {} 🚀", filename); } - self.execute_mir_mode(filename); + runner.execute_mir_mode(filename); return; } // WASM / AOT (feature-gated) - if self.config.compile_wasm { + if runner.config.compile_wasm { #[cfg(feature = "wasm-backend")] - { self.execute_wasm_mode(filename); return; } + { 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 self.config.compile_native { + if runner.config.compile_native { #[cfg(feature = "cranelift-jit")] - { self.execute_aot_mode(filename); return; } + { + use super::super::modes::aot; + aot::execute_aot_mode(runner, 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 self.config.backend.as_str() { + match runner.config.backend.as_str() { "mir" => { if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { println!("🚀 Nyash MIR Interpreter - Executing file: {} 🚀", filename); } - self.execute_mir_mode(filename); + runner.execute_mir_mode(filename); } #[cfg(feature = "cranelift-jit")] "jit-direct" => { @@ -91,7 +94,8 @@ impl NyashRunner { } #[cfg(feature = "cranelift-jit")] { - crate::runner::modes::cranelift::execute_jit_direct_mode(self, filename); + // Use independent JIT-direct runner method (no VM execute loop) + runner.run_file_jit_direct(filename); } #[cfg(not(feature = "cranelift-jit"))] { @@ -103,22 +107,24 @@ impl NyashRunner { if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { println!("⚡ Nyash LLVM Backend - Executing file: {} ⚡", filename); } - self.execute_llvm_mode(filename); + runner.execute_llvm_mode(filename); } _ => { if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { println!("🦀 Nyash Rust Implementation - Executing file: {} 🦀", filename); - if let Some(fuel) = self.config.debug_fuel { + if let Some(fuel) = runner.config.debug_fuel { println!("🔥 Debug fuel limit: {} iterations", fuel); } else { println!("🔥 Debug fuel limit: unlimited"); } println!("===================================================="); } - self.execute_nyash_file(filename); + super::modes::interpreter::execute_nyash_file(filename, runner.config.debug_fuel.clone()); } } } + +impl NyashRunner { pub(crate) fn execute_mir_module(&self, module: &crate::mir::MirModule) { use crate::backend::MirInterpreter; use crate::box_trait::{IntegerBox, BoolBox, StringBox}; diff --git a/src/runner/mod.rs b/src/runner/mod.rs index cb12026d..78cf016a 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -7,7 +7,7 @@ use nyash_rust::cli::CliConfig; use nyash_rust::{ - box_trait::{NyashBox, StringBox, IntegerBox, BoolBox, VoidBox, AddBox, BoxCore}, + box_trait::{StringBox, IntegerBox, BoolBox, VoidBox, AddBox}, tokenizer::{NyashTokenizer}, ast::ASTNode, parser::NyashParser, @@ -41,7 +41,7 @@ mod selfhost; // v2 plugin system imports use nyash_rust::runtime; use nyash_rust::runner_plugin_init; -use std::path::PathBuf; +// use std::path::PathBuf; // not used in current runner /// Resolve a using target according to priority: modules > relative > using-paths /// Returns Ok(resolved_path_or_token). On strict mode, ambiguous matches cause error. @@ -73,7 +73,7 @@ impl NyashRunner { } // Using/module overrides pre-processing let mut using_ctx = self.init_using_context(); - let mut pending_using: Vec<(String, Option)> = Vec::new(); + let pending_using: Vec<(String, Option)> = Vec::new(); for (ns, path) in using_ctx.pending_modules.iter() { let sb = crate::box_trait::StringBox::new(path.clone()); crate::runtime::modules_registry::set(ns.clone(), Box::new(sb)); @@ -350,432 +350,10 @@ impl NyashRunner { // init_bid_plugins moved to runner_plugin_init.rs /// Execute file-based mode with backend selection - - // demo runner moved to runner/demos.rs - - /// 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(); - eprintln!("🔍 DEBUG: Starting execution..."); - match interpreter.execute(ast) { - Ok(result) => { - println!("✅ Execution completed successfully!"); - println!("Result: {}", result.to_string_box().value); - // Structured concurrency: best-effort join of spawned tasks at program end - let join_ms: u64 = std::env::var("NYASH_JOIN_ALL_MS").ok().and_then(|s| s.parse().ok()).unwrap_or(2000); - nyash_rust::runtime::global_hooks::join_all_registered_futures(join_ms); - }, - Err(e) => { - // Use enhanced error reporting with source context - eprintln!("❌ Runtime error:\n{}", e.detailed_message(Some(&code))); - process::exit(1); - } - } + pub(crate) fn run_file(&self, filename: &str) { + dispatch::execute_file_with_backend(self, filename); } - /// 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::() { - ("Float", format!("{}", fb.value)) - } else if let Some(ib) = result.as_any().downcast_ref::() { - ("Float", format!("{}", ib.value as f64)) - } else { ("Float", result.to_string_box().value) } - } - MirType::Integer => { - if let Some(ib) = result.as_any().downcast_ref::() { - ("Integer", ib.value.to_string()) - } else { ("Integer", result.to_string_box().value) } - } - MirType::Bool => { - if let Some(bb) = result.as_any().downcast_ref::() { - ("Bool", bb.value.to_string()) - } else if let Some(ib) = result.as_any().downcast_ref::() { - ("Bool", (ib.value != 0).to_string()) - } else { ("Bool", result.to_string_box().value) } - } - MirType::String => { - if let Some(sb) = result.as_any().downcast_ref::() { - ("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); } - } - 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(), - 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-inkwell-legacy")] - { - 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::() { - 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-inkwell-legacy"))] - { - // 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-inkwell-legacy"); - println!(" and ensure LLVM 18 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" }); - } - - // execute_mir_module moved to runner/dispatch.rs - /// Minimal AOT build pipeline driven by nyash.toml (mvp) fn run_build_mvp(&self, cfg_path: &str) -> Result<(), String> { build::run_build_mvp_impl(self, cfg_path) @@ -817,7 +395,6 @@ impl NyashRunner { // 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; diff --git a/src/runner/modes/interpreter.rs b/src/runner/modes/interpreter.rs new file mode 100644 index 00000000..fefd9bbc --- /dev/null +++ b/src/runner/modes/interpreter.rs @@ -0,0 +1,70 @@ +use crate::parser::NyashParser; +use crate::interpreter::NyashInterpreter; +use std::{fs, process}; + +/// Execute Nyash file with interpreter +pub fn execute_nyash_file(filename: &str, debug_fuel: Option) { + // 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: {:?}...", debug_fuel); + let ast = match NyashParser::parse_from_string_with_fuel(&code, 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(); + eprintln!("🔍 DEBUG: Starting execution..."); + match interpreter.execute(ast) { + Ok(result) => { + println!("✅ Execution completed successfully!"); + println!("Result: {}", result.to_string_box().value); + // Structured concurrency: best-effort join of spawned tasks at program end + let join_ms: u64 = std::env::var("NYASH_JOIN_ALL_MS").ok().and_then(|s| s.parse().ok()).unwrap_or(2000); + crate::runtime::global_hooks::join_all_registered_futures(join_ms); + }, + Err(e) => { + // Use enhanced error reporting with source context + eprintln!("❌ Runtime error:\n{}", e.detailed_message(Some(&code))); + process::exit(1); + } + } +} diff --git a/src/runner/modes/llvm.rs b/src/runner/modes/llvm.rs index 244489f0..0cea2082 100644 --- a/src/runner/modes/llvm.rs +++ b/src/runner/modes/llvm.rs @@ -1,5 +1,5 @@ use super::super::NyashRunner; -use nyash_rust::{parser::NyashParser, mir::{MirCompiler, MirInstruction}, box_trait::IntegerBox}; +use nyash_rust::{parser::NyashParser, mir::{MirCompiler, MirInstruction}}; use nyash_rust::mir::passes::method_id_inject::inject_method_ids; use std::{fs, process}; @@ -40,13 +40,13 @@ impl NyashRunner { } // If explicit object path is requested, emit object only - if let Ok(out_path) = std::env::var("NYASH_LLVM_OBJ_OUT") { + 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. let use_harness = std::env::var("NYASH_LLVM_USE_HARNESS").ok().as_deref() == Some("1"); if use_harness { - if let Some(parent) = std::path::Path::new(&out_path).parent() { let _ = std::fs::create_dir_all(parent); } + if let Some(parent) = std::path::Path::new(&_out_path).parent() { let _ = std::fs::create_dir_all(parent); } let py = which::which("python3").ok(); if let Some(py3) = py { let harness = std::path::Path::new("tools/llvmlite_harness.py"); @@ -60,29 +60,29 @@ impl NyashRunner { process::exit(1); } if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { - eprintln!("[Runner/LLVM] using llvmlite harness → {} (mir={})", out_path, mir_json_path.display()); + eprintln!("[Runner/LLVM] using llvmlite harness → {} (mir={})", _out_path, mir_json_path.display()); } // 2) Run harness with --in/--out(失敗時は即エラー) let status = std::process::Command::new(py3) - .args([harness.to_string_lossy().as_ref(), "--in", &mir_json_path.display().to_string(), "--out", &out_path]) + .args([harness.to_string_lossy().as_ref(), "--in", &mir_json_path.display().to_string(), "--out", &_out_path]) .status().map_err(|e| format!("spawn harness: {}", e)).unwrap(); if !status.success() { eprintln!("❌ llvmlite harness failed (status={})", status.code().unwrap_or(-1)); process::exit(1); } // Verify - match std::fs::metadata(&out_path) { - Ok(meta) if meta.len() > 0 => { - if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { - eprintln!("[LLVM] object emitted by harness: {} ({} bytes)", out_path, meta.len()); + match std::fs::metadata(&_out_path) { + Ok(meta) if meta.len() > 0 => { + if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { + eprintln!("[LLVM] object emitted by harness: {} ({} bytes)", _out_path, meta.len()); + } + return; + } + _ => { + eprintln!("❌ harness output not found or empty: {}", _out_path); + process::exit(1); } - return; } - _ => { - eprintln!("❌ harness output not found or empty: {}", out_path); - process::exit(1); - } - } } else { eprintln!("❌ harness script not found: {}", harness.display()); process::exit(1); @@ -92,18 +92,18 @@ impl NyashRunner { process::exit(1); } // Verify object presence and size (>0) - match std::fs::metadata(&out_path) { + match std::fs::metadata(&_out_path) { Ok(meta) => { if meta.len() == 0 { - eprintln!("❌ harness object is empty: {}", out_path); + 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()); + eprintln!("[LLVM] object emitted: {} ({} bytes)", _out_path, meta.len()); } } Err(e) => { - eprintln!("❌ harness output not found after emit: {} ({})", out_path, e); + eprintln!("❌ harness output not found after emit: {} ({})", _out_path, e); process::exit(1); } } @@ -113,23 +113,23 @@ impl NyashRunner { { 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() { + if let Some(parent) = std::path::Path::new(&_out_path).parent() { let _ = std::fs::create_dir_all(parent); } if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { - eprintln!("[Runner/LLVM] emitting object to {} (cwd={})", out_path, std::env::current_dir().map(|p| p.display().to_string()).unwrap_or_default()); + eprintln!("[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) { + 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) { + match std::fs::metadata(&_out_path) { Ok(meta) if meta.len() > 0 => { if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { - eprintln!("[LLVM] object emitted: {} ({} bytes)", out_path, meta.len()); + eprintln!("[LLVM] object emitted: {} ({} bytes)", _out_path, meta.len()); } } - _ => { eprintln!("❌ LLVM object not found or empty: {}", out_path); process::exit(1); } + _ => { eprintln!("❌ LLVM object not found or empty: {}", _out_path); process::exit(1); } } return; } diff --git a/src/runner/modes/mod.rs b/src/runner/modes/mod.rs index 0f4ee68b..afc3ad35 100644 --- a/src/runner/modes/mod.rs +++ b/src/runner/modes/mod.rs @@ -1,12 +1,5 @@ +pub mod interpreter; pub mod mir; -pub mod mir_interpreter; pub mod vm; pub mod llvm; pub mod bench; -pub mod common; -#[cfg(feature = "wasm-backend")] -pub mod wasm; -#[cfg(feature = "cranelift-jit")] -pub mod aot; -#[cfg(feature = "cranelift-jit")] -pub mod cranelift; diff --git a/src/runner/modes/vm.rs b/src/runner/modes/vm.rs index 00a66d11..e90c90f8 100644 --- a/src/runner/modes/vm.rs +++ b/src/runner/modes/vm.rs @@ -107,7 +107,7 @@ impl NyashRunner { // Optional: dump MIR for diagnostics if std::env::var("NYASH_VM_DUMP_MIR").ok().as_deref() == Some("1") { - let mut p = nyash_rust::mir::MirPrinter::new(); + let p = nyash_rust::mir::MirPrinter::new(); eprintln!("{}", p.print_module(&compile_result.module)); }