refactor: Gemini/ChatGPT collaborative refactoring + build fixes

Major changes:
- Split runner module: 1358→580 lines (via Gemini)
- Create new modules: dispatch.rs, selfhost.rs, pipeline.rs, pipe_io.rs
- Fix build errors from incomplete method migrations
- Add warning to CLAUDE.md about JIT/Cranelift not working
- Create interpreter.rs mode module
- Refactor loop builder into separate module

Build status:
-  Executable builds successfully
-  Basic execution works (tested with print)
- ⚠️ 106 warnings remain (to be cleaned up next)
- ⚠️ execute_mir_mode still in mod.rs (needs further migration)

Note: ChatGPT correctly fixed runner.execute_mir_mode() calls
that I incorrectly changed to super::modes::mir::

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Selfhosting Dev
2025-09-16 03:54:44 +09:00
parent f9bd13f4e4
commit 40db299bab
22 changed files with 425 additions and 613 deletions

View File

@ -518,6 +518,11 @@ codex exec "質問内容"
llvmliteベースのLLVMバックエンド実装。箱理論により650行→100行の簡略化を実現 llvmliteベースのLLVMバックエンド実装。箱理論により650行→100行の簡略化を実現
Rust/inkwellの複雑さを回避して、シンプルに2000行程度でMIR14→LLVM変換を実現。 Rust/inkwellの複雑さを回避して、シンプルに2000行程度でMIR14→LLVM変換を実現。
⚠️ **重要**: **JIT/Craneliftは現在まともに動作しません**
- ビルドは可能(`cargo build --release --features cranelift-jit`
- 実行は不可(内部実装が未完成)
- **Python LLVMルートとPyVMのみが現在の開発対象です**
#### 実行方法 #### 実行方法
```bash ```bash
cd src/llvm_py cd src/llvm_py

View File

@ -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::helpers::{as_float, as_int, map_type};
use super::LLVMCompiler; use super::LLVMCompiler;
use crate::backend::llvm::context::CodegenContext; use crate::backend::llvm::context::CodegenContext;
@ -1115,7 +1124,6 @@ impl LLVMCompiler {
} }
} }
} }
Old duplicate lowering block removed
*/ */
#[cfg(test)] #[cfg(test)]
@ -1128,3 +1136,160 @@ mod tests {
assert!(compiler.is_ok()); 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<Self, String> {
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<String, FunctionValue> = 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<BasicTypeEnum> = 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(&param_vals, false),
BasicTypeEnum::FloatType(t) => t.fn_type(&param_vals, false),
BasicTypeEnum::PointerType(t) => t.fn_type(&param_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());
}
}

View File

@ -28,7 +28,7 @@ struct Inner {
/// Used for non-owning registries (TaskGroup/implicit group) to avoid leaks. /// Used for non-owning registries (TaskGroup/implicit group) to avoid leaks.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct FutureWeak { pub struct FutureWeak {
pub(crate) inner: Weak<Inner>, inner: Weak<Inner>,
} }
impl Clone for NyashFutureBox { impl Clone for NyashFutureBox {

View File

@ -31,6 +31,7 @@ pub(crate) fn debug_log(msg: &str) {
} }
// Conditional debug macro - unified with utils::debug_on() // Conditional debug macro - unified with utils::debug_on()
#[allow(unused_macros)]
macro_rules! debug_trace { macro_rules! debug_trace {
($($arg:tt)*) => { ($($arg:tt)*) => {
if crate::interpreter::utils::debug_on() { eprintln!($($arg)*); } if crate::interpreter::utils::debug_on() { eprintln!($($arg)*); }

View File

@ -1,7 +1,7 @@
//! Evaluation entry points: execute program and nodes //! Evaluation entry points: execute program and nodes
use crate::ast::ASTNode; use crate::ast::ASTNode;
use crate::box_trait::{NyashBox, VoidBox, StringBox}; use crate::box_trait::{NyashBox, VoidBox};
use super::{NyashInterpreter, RuntimeError, ControlFlow}; use super::{NyashInterpreter, RuntimeError, ControlFlow};
impl NyashInterpreter { impl NyashInterpreter {

View File

@ -22,7 +22,7 @@ use std::sync::Arc;
impl NyashInterpreter { impl NyashInterpreter {
/// Build closure environment by capturing 'me' and free variables by value (P1) /// Build closure environment by capturing 'me' and free variables by value (P1)
fn build_closure_env(&mut self, params: &Vec<String>, body: &Vec<ASTNode>) -> Result<crate::boxes::function_box::ClosureEnv, RuntimeError> { fn build_closure_env(&mut self, params: &Vec<String>, body: &Vec<ASTNode>) -> Result<crate::boxes::function_box::ClosureEnv, RuntimeError> {
use std::collections::{HashSet, VecDeque}; use std::collections::HashSet;
let mut env = crate::boxes::function_box::ClosureEnv::new(); let mut env = crate::boxes::function_box::ClosureEnv::new();
// Capture 'me' if bound // Capture 'me' if bound
if let Ok(mev) = self.resolve_variable("me") { env.me_value = Some(Arc::downgrade(&mev)); } if let Ok(mev) = self.resolve_variable("me") { env.me_value = Some(Arc::downgrade(&mev)); }

View File

@ -8,7 +8,6 @@ use crate::interpreter::RuntimeError;
use crate::ast::ASTNode; use crate::ast::ASTNode;
use crate::box_trait::{NyashBox, StringBox}; use crate::box_trait::{NyashBox, StringBox};
use crate::boxes::{IntentBox, P2PBox}; use crate::boxes::{IntentBox, P2PBox};
use crate::box_trait::BoolBox;
impl NyashInterpreter { impl NyashInterpreter {
/// IntentBoxのメソッド実行 (RwLock版) /// IntentBoxのメソッド実行 (RwLock版)

View File

@ -7,7 +7,7 @@
*/ */
use crate::ast::ASTNode; 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::gc_config_box::GcConfigBox;
use crate::boxes::debug_config_box::DebugConfigBox; use crate::boxes::debug_config_box::DebugConfigBox;
use crate::interpreter::{NyashInterpreter, RuntimeError}; use crate::interpreter::{NyashInterpreter, RuntimeError};
@ -168,4 +168,4 @@ impl NyashInterpreter {
}), }),
} }
} }
} }

View File

@ -19,7 +19,6 @@ use crate::boxes::debug_box::DebugBox;
// WASM-specific Box types (conditionally included) // WASM-specific Box types (conditionally included)
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use crate::boxes::web::{WebDisplayBox, WebConsoleBox, WebCanvasBox}; use crate::boxes::web::{WebDisplayBox, WebConsoleBox, WebCanvasBox};
use crate::finalization;
use crate::exception_box; use crate::exception_box;
use std::collections::HashMap; use std::collections::HashMap;

View File

@ -5,13 +5,12 @@
*/ */
use super::{ use super::{
MirInstruction, BasicBlock, BasicBlockId, MirFunction, MirModule, MirInstruction, BasicBlock, BasicBlockId, MirFunction, MirModule,
FunctionSignature, ValueId, ConstValue, BinaryOp, UnaryOp, CompareOp, FunctionSignature, ValueId, ConstValue, CompareOp,
MirType, EffectMask, Effect, BasicBlockIdGenerator, ValueIdGenerator 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 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::HashMap;
use std::collections::HashSet; use std::collections::HashSet;
use std::fs; use std::fs;
@ -30,6 +29,7 @@ mod exprs_lambda; // lambda lowering
mod exprs_include; // include lowering mod exprs_include; // include lowering
mod plugin_sigs; // plugin signature loader mod plugin_sigs; // plugin signature loader
mod vars; // variables/scope helpers mod vars; // variables/scope helpers
pub(crate) mod loops; // small loop helpers (header/exit context)
// moved helpers to builder/utils.rs // moved helpers to builder/utils.rs
@ -90,62 +90,6 @@ pub struct MirBuilder {
} }
impl MirBuilder { impl MirBuilder {
/// Emit a Box method call (unified: BoxCall)
fn emit_box_or_plugin_call(
&mut self,
dst: Option<ValueId>,
box_val: ValueId,
method: String,
method_id: Option<u16>,
args: Vec<ValueId>,
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<String> = 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<super::MirType> = 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 /// Create a new MIR builder
pub fn new() -> Self { pub fn new() -> Self {
let plugin_method_sigs = plugin_sigs::load_plugin_method_sigs(); 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<ValueId, String> {
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<ValueId, String> {
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<ValueId, String> {
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<ValueId, String> {
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 // moved to builder_calls.rs: lower_method_as_function

View File

@ -1,5 +1,5 @@
// Declarations lowering: static boxes and box declarations // Declarations lowering: static boxes and box declarations
use super::{MirInstruction, ConstValue, ValueId, BasicBlockId}; use super::{MirInstruction, ConstValue, ValueId};
use crate::ast::ASTNode; use crate::ast::ASTNode;
use std::collections::HashSet; use std::collections::HashSet;
use crate::mir::slot_registry::{get_or_assign_type_id, reserve_method_slot}; use crate::mir::slot_registry::{get_or_assign_type_id, reserve_method_slot};

View File

@ -1,6 +1,6 @@
// Expression lowering split from builder.rs to keep files lean // Expression lowering split from builder.rs to keep files lean
use super::{MirInstruction, ConstValue, BasicBlockId, ValueId}; use super::{MirInstruction, ConstValue, ValueId};
use crate::ast::{ASTNode, LiteralValue}; use crate::ast::ASTNode;
impl super::MirBuilder { impl super::MirBuilder {
// Main expression dispatcher // Main expression dispatcher

24
src/mir/builder/loops.rs Normal file
View File

@ -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<BasicBlockId> {
builder.loop_header_stack.last().copied()
}
/// Peek current loop exit block id
pub(crate) fn current_exit(builder: &super::MirBuilder) -> Option<BasicBlockId> {
builder.loop_exit_stack.last().copied()
}

View File

@ -1,5 +1,6 @@
use std::fs; use std::fs;
use super::{BasicBlock, BasicBlockId}; use super::{BasicBlock, BasicBlockId};
use crate::mir::{TypeOpKind, WeakRefOp, BarrierOp};
// Resolve include path using nyash.toml include.roots if present // Resolve include path using nyash.toml include.roots if present
pub(super) fn resolve_include_path_builder(filename: &str) -> String { 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<super::ValueId>,
box_val: super::ValueId,
method: String,
method_id: Option<u16>,
args: Vec<super::ValueId>,
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<String> = 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<super::MirType> = 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<super::ValueId, String> {
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<super::ValueId, String> {
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<super::ValueId, String> {
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<super::ValueId, String> {
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 })
}
}

View File

@ -67,9 +67,8 @@ impl<'a> LoopBuilder<'a> {
let after_loop_id = self.new_block(); let after_loop_id = self.new_block();
self.loop_header = Some(header_id); self.loop_header = Some(header_id);
self.continue_snapshots.clear(); 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) // 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 へのジャンプ // 2. Preheader -> Header へのジャンプ
self.emit_jump(header_id)?; self.emit_jump(header_id)?;
@ -119,9 +118,7 @@ impl<'a> LoopBuilder<'a> {
// 10. ループ後の処理 // 10. ループ後の処理
self.set_current_block(after_loop_id)?; self.set_current_block(after_loop_id)?;
// Pop loop context // Pop loop context
let _ = self.parent_builder.loop_header_stack.pop(); crate::mir::builder::loops::pop_loop_context(self.parent_builder);
// loop exit stack mirrors header stack; maintain symmetry
let _ = self.parent_builder.loop_exit_stack.pop();
// void値を返す // void値を返す
let void_dst = self.new_value(); let void_dst = self.new_value();
@ -386,12 +383,12 @@ impl<'a> LoopBuilder<'a> {
// Jump to loop exit (after_loop_id) if available // Jump to loop exit (after_loop_id) if available
let cur_block = self.current_block()?; let cur_block = self.current_block()?;
// Ensure parent has recorded current loop exit; if not, record now // 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: // Determine after_loop by peeking the next id used earlier:
// In this builder, after_loop_id was created above; record it for nested lowering // 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 // 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)?; self.emit_jump(exit_bb)?;
let _ = self.add_predecessor(exit_bb, cur_block); let _ = self.add_predecessor(exit_bb, cur_block);
} }

View File

@ -45,7 +45,7 @@ pub fn inject_method_ids(module: &mut MirModule) -> usize {
let mid_u16 = if let Some(h) = host_guard.as_ref() { let mid_u16 = if let Some(h) = host_guard.as_ref() {
// Try resolve via plugin config (may fail for builtins) // Try resolve via plugin config (may fail for builtins)
match h.resolve_method(&bt, method) { 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), Err(_) => resolve_slot_by_type_name(&bt, method),
} }
} else { } else {
@ -63,7 +63,7 @@ pub fn inject_method_ids(module: &mut MirModule) -> usize {
// Resolve id as above // Resolve id as above
let mid_u16 = if let Some(h) = host_guard.as_ref() { let mid_u16 = if let Some(h) = host_guard.as_ref() {
match h.resolve_method(&bt, method) { 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), Err(_) => resolve_slot_by_type_name(&bt, method),
} }
} else { } else {
@ -91,4 +91,3 @@ pub fn inject_method_ids(module: &mut MirModule) -> usize {
injected injected
} }

View File

@ -7,12 +7,11 @@ use crate::runner::json_v0_bridge;
use nyash_rust::parser::NyashParser; use nyash_rust::parser::NyashParser;
use std::{fs, process}; use std::{fs, process};
impl NyashRunner { /// Thin file dispatcher: select backend and delegate to mode executors
/// Thin file dispatcher: select backend and delegate to mode executors pub(crate) fn execute_file_with_backend(runner: &NyashRunner, filename: &str) {
pub(crate) fn run_file(&self, filename: &str) {
// Selfhost pipeline (Ny -> JSON v0) behind env gate // Selfhost pipeline (Ny -> JSON v0) behind env gate
if std::env::var("NYASH_USE_NY_COMPILER").ok().as_deref() == Some("1") { 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; return;
} else if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { } 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)"); 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 // 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 { if use_ny_parser {
let code = match fs::read_to_string(filename) { let code = match fs::read_to_string(filename) {
Ok(content) => content, Ok(content) => content,
@ -31,7 +30,7 @@ impl NyashRunner {
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
println!("🚀 Nyash MIR Interpreter - (parser=ny) Executing file: {} 🚀", filename); println!("🚀 Nyash MIR Interpreter - (parser=ny) Executing file: {} 🚀", filename);
} }
self.execute_mir_module(&module); runner.execute_mir_module(&module);
return; return;
} }
Err(e) => { eprintln!("❌ Direct bridge parse error: {}", e); process::exit(1); } Err(e) => { eprintln!("❌ Direct bridge parse error: {}", e); process::exit(1); }
@ -39,7 +38,7 @@ impl NyashRunner {
} }
// AST dump mode // AST dump mode
if self.config.dump_ast { if runner.config.dump_ast {
println!("🧠 Nyash AST Dump - Processing file: {}", filename); println!("🧠 Nyash AST Dump - Processing file: {}", filename);
let code = match fs::read_to_string(filename) { let code = match fs::read_to_string(filename) {
Ok(content) => content, Ok(content) => content,
@ -54,35 +53,39 @@ impl NyashRunner {
} }
// MIR dump/verify // 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") { if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
println!("🚀 Nyash MIR Compiler - Processing file: {} 🚀", filename); println!("🚀 Nyash MIR Compiler - Processing file: {} 🚀", filename);
} }
self.execute_mir_mode(filename); runner.execute_mir_mode(filename);
return; return;
} }
// WASM / AOT (feature-gated) // WASM / AOT (feature-gated)
if self.config.compile_wasm { if runner.config.compile_wasm {
#[cfg(feature = "wasm-backend")] #[cfg(feature = "wasm-backend")]
{ self.execute_wasm_mode(filename); return; } { super::modes::wasm::execute_wasm_mode(runner, filename); return; }
#[cfg(not(feature = "wasm-backend"))] #[cfg(not(feature = "wasm-backend"))]
{ eprintln!("❌ WASM backend not available. Please rebuild with: cargo build --features wasm-backend"); process::exit(1); } { 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")] #[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"))] #[cfg(not(feature = "cranelift-jit"))]
{ eprintln!("❌ Native AOT compilation requires Cranelift. Please rebuild: cargo build --features cranelift-jit"); process::exit(1); } { eprintln!("❌ Native AOT compilation requires Cranelift. Please rebuild: cargo build --features cranelift-jit"); process::exit(1); }
} }
// Backend selection // Backend selection
match self.config.backend.as_str() { match runner.config.backend.as_str() {
"mir" => { "mir" => {
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
println!("🚀 Nyash MIR Interpreter - Executing file: {} 🚀", filename); println!("🚀 Nyash MIR Interpreter - Executing file: {} 🚀", filename);
} }
self.execute_mir_mode(filename); runner.execute_mir_mode(filename);
} }
#[cfg(feature = "cranelift-jit")] #[cfg(feature = "cranelift-jit")]
"jit-direct" => { "jit-direct" => {
@ -91,7 +94,8 @@ impl NyashRunner {
} }
#[cfg(feature = "cranelift-jit")] #[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"))] #[cfg(not(feature = "cranelift-jit"))]
{ {
@ -103,22 +107,24 @@ impl NyashRunner {
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
println!("⚡ Nyash LLVM Backend - Executing file: {}", filename); 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") { if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
println!("🦀 Nyash Rust Implementation - Executing file: {} 🦀", filename); 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); println!("🔥 Debug fuel limit: {} iterations", fuel);
} else { } else {
println!("🔥 Debug fuel limit: unlimited"); println!("🔥 Debug fuel limit: unlimited");
} }
println!("===================================================="); 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) { pub(crate) fn execute_mir_module(&self, module: &crate::mir::MirModule) {
use crate::backend::MirInterpreter; use crate::backend::MirInterpreter;
use crate::box_trait::{IntegerBox, BoolBox, StringBox}; use crate::box_trait::{IntegerBox, BoolBox, StringBox};

View File

@ -7,7 +7,7 @@
use nyash_rust::cli::CliConfig; use nyash_rust::cli::CliConfig;
use nyash_rust::{ use nyash_rust::{
box_trait::{NyashBox, StringBox, IntegerBox, BoolBox, VoidBox, AddBox, BoxCore}, box_trait::{StringBox, IntegerBox, BoolBox, VoidBox, AddBox},
tokenizer::{NyashTokenizer}, tokenizer::{NyashTokenizer},
ast::ASTNode, ast::ASTNode,
parser::NyashParser, parser::NyashParser,
@ -41,7 +41,7 @@ mod selfhost;
// v2 plugin system imports // v2 plugin system imports
use nyash_rust::runtime; use nyash_rust::runtime;
use nyash_rust::runner_plugin_init; 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 /// Resolve a using target according to priority: modules > relative > using-paths
/// Returns Ok(resolved_path_or_token). On strict mode, ambiguous matches cause error. /// Returns Ok(resolved_path_or_token). On strict mode, ambiguous matches cause error.
@ -73,7 +73,7 @@ impl NyashRunner {
} }
// Using/module overrides pre-processing // Using/module overrides pre-processing
let mut using_ctx = self.init_using_context(); let mut using_ctx = self.init_using_context();
let mut pending_using: Vec<(String, Option<String>)> = Vec::new(); let pending_using: Vec<(String, Option<String>)> = Vec::new();
for (ns, path) in using_ctx.pending_modules.iter() { for (ns, path) in using_ctx.pending_modules.iter() {
let sb = crate::box_trait::StringBox::new(path.clone()); let sb = crate::box_trait::StringBox::new(path.clone());
crate::runtime::modules_registry::set(ns.clone(), Box::new(sb)); 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 // init_bid_plugins moved to runner_plugin_init.rs
/// Execute file-based mode with backend selection /// Execute file-based mode with backend selection
pub(crate) fn run_file(&self, filename: &str) {
// demo runner moved to runner/demos.rs dispatch::execute_file_with_backend(self, filename);
/// 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);
}
}
} }
/// 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); }
}
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::<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-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) /// Minimal AOT build pipeline driven by nyash.toml (mvp)
fn run_build_mvp(&self, cfg_path: &str) -> Result<(), String> { fn run_build_mvp(&self, cfg_path: &str) -> Result<(), String> {
build::run_build_mvp_impl(self, cfg_path) 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 // Guard: refuse write-effects in jit-direct when policy.read_only
{ {
use nyash_rust::mir::MirInstruction;
use nyash_rust::mir::effect::Effect; use nyash_rust::mir::effect::Effect;
let policy = nyash_rust::jit::policy::current(); let policy = nyash_rust::jit::policy::current();
let mut writes = 0usize; let mut writes = 0usize;

View File

@ -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<usize>) {
// 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);
}
}
}

View File

@ -1,5 +1,5 @@
use super::super::NyashRunner; 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 nyash_rust::mir::passes::method_id_inject::inject_method_ids;
use std::{fs, process}; use std::{fs, process};
@ -40,13 +40,13 @@ impl NyashRunner {
} }
// If explicit object path is requested, emit object only // 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")] #[cfg(feature = "llvm-harness")]
{ {
// Harness path (optional): if NYASH_LLVM_USE_HARNESS=1, try Python/llvmlite first. // 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"); let use_harness = std::env::var("NYASH_LLVM_USE_HARNESS").ok().as_deref() == Some("1");
if use_harness { 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(); let py = which::which("python3").ok();
if let Some(py3) = py { if let Some(py3) = py {
let harness = std::path::Path::new("tools/llvmlite_harness.py"); let harness = std::path::Path::new("tools/llvmlite_harness.py");
@ -60,29 +60,29 @@ impl NyashRunner {
process::exit(1); process::exit(1);
} }
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("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失敗時は即エラー // 2) Run harness with --in/--out失敗時は即エラー
let status = std::process::Command::new(py3) 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(); .status().map_err(|e| format!("spawn harness: {}", e)).unwrap();
if !status.success() { if !status.success() {
eprintln!("❌ llvmlite harness failed (status={})", status.code().unwrap_or(-1)); eprintln!("❌ llvmlite harness failed (status={})", status.code().unwrap_or(-1));
process::exit(1); process::exit(1);
} }
// Verify // Verify
match std::fs::metadata(&out_path) { match std::fs::metadata(&_out_path) {
Ok(meta) if meta.len() > 0 => { Ok(meta) if meta.len() > 0 => {
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
eprintln!("[LLVM] object emitted by harness: {} ({} bytes)", out_path, meta.len()); 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 { } else {
eprintln!("❌ harness script not found: {}", harness.display()); eprintln!("❌ harness script not found: {}", harness.display());
process::exit(1); process::exit(1);
@ -92,18 +92,18 @@ impl NyashRunner {
process::exit(1); process::exit(1);
} }
// Verify object presence and size (>0) // Verify object presence and size (>0)
match std::fs::metadata(&out_path) { match std::fs::metadata(&_out_path) {
Ok(meta) => { Ok(meta) => {
if meta.len() == 0 { if meta.len() == 0 {
eprintln!("❌ harness object is empty: {}", out_path); eprintln!("❌ harness object is empty: {}", _out_path);
process::exit(1); process::exit(1);
} }
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("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) => { 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); process::exit(1);
} }
} }
@ -113,23 +113,23 @@ impl NyashRunner {
{ {
use nyash_rust::backend::llvm_compile_to_object; use nyash_rust::backend::llvm_compile_to_object;
// Ensure parent directory exists for the object file // 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); let _ = std::fs::create_dir_all(parent);
} }
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { 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); eprintln!("❌ LLVM object emit error: {}", e);
process::exit(1); process::exit(1);
} }
match std::fs::metadata(&out_path) { match std::fs::metadata(&_out_path) {
Ok(meta) if meta.len() > 0 => { Ok(meta) if meta.len() > 0 => {
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("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());
} }
} }
_ => { 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; return;
} }

View File

@ -1,12 +1,5 @@
pub mod interpreter;
pub mod mir; pub mod mir;
pub mod mir_interpreter;
pub mod vm; pub mod vm;
pub mod llvm; pub mod llvm;
pub mod bench; 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;

View File

@ -107,7 +107,7 @@ impl NyashRunner {
// Optional: dump MIR for diagnostics // Optional: dump MIR for diagnostics
if std::env::var("NYASH_VM_DUMP_MIR").ok().as_deref() == Some("1") { 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)); eprintln!("{}", p.print_module(&compile_result.module));
} }