🏗️ feat: Phase 9.78b準備 - インタープリター・VM統合アーキテクチャ設計

Phase 9.78b: Codexの天才的分析に基づくアーキテクチャ再設計準備

## 📋 実施内容
1. Codex分析結果のアーカイブ
   - 実装詳細共有 → モデル共有・実行時共有への転換提案
   - 8ステップの段階的実装計画

2. Phase 9.78a作業の保存
   - MIR生成でのNewBox命令統一(保持)
   - ScopeTracker基本実装(一時コメントアウト)
   - VM拡張の方向性(TODOコメント付き)

3. ビルドエラー修正
   - ScopeTrackerインポート問題を一時的に解決
   - ビルド成功(警告のみ)

## 📚 作成ドキュメント
- architecture-redesign-proposal.md - Codexの設計提案
- phase_9_78b_interpreter_architecture_refactoring.md - 実装計画
- codex-analysis/* - 分析結果アーカイブ

## 🎯 次のステップ
Phase 9.78b Step 1: BoxDeclarationをcore::modelへ移動
This commit is contained in:
Moe Charm
2025-08-20 17:58:51 +09:00
parent c11b68af90
commit 86b9f7719b
13 changed files with 1478 additions and 1158 deletions

View File

@ -7,8 +7,18 @@
use crate::mir::{MirModule, MirFunction, MirInstruction, ConstValue, BinaryOp, CompareOp, UnaryOp, ValueId, BasicBlockId};
use crate::box_trait::{NyashBox, StringBox, IntegerBox, BoolBox, VoidBox};
use std::collections::HashMap;
use std::sync::Arc;
use super::vm_phi::LoopExecutor;
// Phase 9.78a: Import necessary components for unified Box handling
// TODO: Re-enable when interpreter refactoring is complete
// use crate::box_factory::UnifiedBoxRegistry;
// use crate::instance_v2::InstanceBox;
// use crate::interpreter::BoxDeclaration;
// use crate::scope_tracker::ScopeTracker;
// #[cfg(all(feature = "plugins", not(target_arch = "wasm32")))]
// use crate::runtime::plugin_loader_v2::PluginLoaderV2;
/// VM execution error
#[derive(Debug)]
pub enum VMError {
@ -44,6 +54,8 @@ pub enum VMValue {
String(String),
Future(crate::boxes::future::FutureBox),
Void,
// Phase 9.78a: Add BoxRef for complex Box types
BoxRef(Arc<dyn NyashBox>),
}
// Manual PartialEq implementation to avoid requiring PartialEq on FutureBox
@ -57,6 +69,8 @@ impl PartialEq for VMValue {
(VMValue::Void, VMValue::Void) => true,
// Future equality semantics are not defined; treat distinct futures as not equal
(VMValue::Future(_), VMValue::Future(_)) => false,
// BoxRef equality by reference
(VMValue::BoxRef(_), VMValue::BoxRef(_)) => false,
_ => false,
}
}
@ -72,6 +86,8 @@ impl VMValue {
VMValue::String(s) => Box::new(StringBox::new(s)),
VMValue::Future(f) => Box::new(f.clone()),
VMValue::Void => Box::new(VoidBox::new()),
// Phase 9.78a: BoxRef returns cloned Box
VMValue::BoxRef(arc_box) => arc_box.clone_box(),
}
}
@ -84,6 +100,7 @@ impl VMValue {
VMValue::String(s) => s.clone(),
VMValue::Future(f) => f.to_string_box().value,
VMValue::Void => "void".to_string(),
VMValue::BoxRef(arc_box) => arc_box.to_string_box().value,
}
}
@ -106,7 +123,7 @@ impl VMValue {
/// Convert from NyashBox to VMValue
pub fn from_nyash_box(nyash_box: Box<dyn crate::box_trait::NyashBox>) -> VMValue {
// Try to downcast to known types
// Try to downcast to known types for optimization
if let Some(int_box) = nyash_box.as_any().downcast_ref::<IntegerBox>() {
VMValue::Integer(int_box.value)
} else if let Some(bool_box) = nyash_box.as_any().downcast_ref::<BoolBox>() {
@ -116,8 +133,8 @@ impl VMValue {
} else if let Some(future_box) = nyash_box.as_any().downcast_ref::<crate::boxes::future::FutureBox>() {
VMValue::Future(future_box.clone())
} else {
// For any other type, convert to string representation
VMValue::String(nyash_box.to_string_box().value)
// Phase 9.78a: For all other Box types (user-defined, plugin), store as BoxRef
VMValue::BoxRef(Arc::from(nyash_box))
}
}
}
@ -154,6 +171,17 @@ pub struct VM {
object_fields: HashMap<ValueId, HashMap<String, VMValue>>,
/// Loop executor for handling phi nodes and loop-specific logic
loop_executor: LoopExecutor,
// Phase 9.78a: Add unified Box handling components
// TODO: Re-enable when interpreter refactoring is complete
// /// Box registry for creating all Box types
// box_registry: Arc<UnifiedBoxRegistry>,
// /// Plugin loader for external Box types
// #[cfg(all(feature = "plugins", not(target_arch = "wasm32")))]
// plugin_loader: Option<Arc<PluginLoaderV2>>,
// Scope tracker for lifecycle management
// scope_tracker: ScopeTracker,
// /// Box declarations from the AST
// box_declarations: Arc<RwLock<HashMap<String, BoxDeclaration>>>,
}
impl VM {
@ -168,9 +196,38 @@ impl VM {
last_result: None,
object_fields: HashMap::new(),
loop_executor: LoopExecutor::new(),
// TODO: Re-enable when interpreter refactoring is complete
// box_registry: Arc::new(UnifiedBoxRegistry::new()),
// #[cfg(all(feature = "plugins", not(target_arch = "wasm32")))]
// plugin_loader: None,
// scope_tracker: ScopeTracker::new(),
// box_declarations: Arc::new(RwLock::new(HashMap::new())),
}
}
// TODO: Re-enable when interpreter refactoring is complete
/*
/// Create a new VM instance with Box registry and declarations
pub fn new_with_registry(
box_registry: Arc<UnifiedBoxRegistry>,
box_declarations: Arc<RwLock<HashMap<String, BoxDeclaration>>>
) -> Self {
// Implementation pending interpreter refactoring
unimplemented!()
}
/// Phase 9.78a: Create VM with plugin support
#[cfg(all(feature = "plugins", not(target_arch = "wasm32")))]
pub fn new_with_plugins(
box_registry: Arc<UnifiedBoxRegistry>,
plugin_loader: Arc<PluginLoaderV2>,
box_declarations: Arc<RwLock<HashMap<String, BoxDeclaration>>>,
) -> Self {
// Implementation pending interpreter refactoring
unimplemented!()
}
*/
/// Execute a MIR module
pub fn execute_module(&mut self, module: &MirModule) -> Result<Box<dyn NyashBox>, VMError> {
// Find main function
@ -191,6 +248,9 @@ impl VM {
// Initialize loop executor for this function
self.loop_executor.initialize();
// Phase 9.78a: Enter a new scope for this function
// self.scope_tracker.push_scope();
// Start at entry block
let mut current_block = function.entry_block;
@ -224,6 +284,8 @@ impl VM {
// Handle control flow
if let Some(return_value) = should_return {
// Phase 9.78a: Exit scope before returning
// self.scope_tracker.pop_scope();
return Ok(return_value);
} else if let Some(target) = next_block {
// Update previous block before jumping
@ -234,6 +296,8 @@ impl VM {
} else {
// Block ended without terminator - this shouldn't happen in well-formed MIR
// but let's handle it gracefully by returning void
// Phase 9.78a: Exit scope before returning
// self.scope_tracker.pop_scope();
return Ok(VMValue::Void);
}
}
@ -354,9 +418,16 @@ impl VM {
},
MirInstruction::BoxCall { dst, box_val, method, args, effects: _ } => {
// Phase 9.78a: Unified method dispatch for all Box types
// Get the box value
let box_vm_value = self.get_value(*box_val)?;
let box_nyash = box_vm_value.to_nyash_box();
// Handle BoxRef for proper method dispatch
let box_nyash = match &box_vm_value {
VMValue::BoxRef(arc_box) => arc_box.clone_box(),
_ => box_vm_value.to_nyash_box(),
};
// Evaluate arguments
let mut arg_values = Vec::new();
@ -365,8 +436,8 @@ impl VM {
arg_values.push(arg_vm_value.to_nyash_box());
}
// Call the method - this mimics interpreter method dispatch
let result = self.call_box_method(box_nyash, method, arg_values)?;
// Call the method - unified dispatch for all Box types
let result = self.call_unified_method(box_nyash, method, arg_values)?;
// Store result if destination is specified
if let Some(dst_id) = dst {
@ -376,32 +447,54 @@ impl VM {
Ok(ControlFlow::Continue)
},
MirInstruction::NewBox { dst, box_type, args: _ } => {
// Implement basic box creation for common types
MirInstruction::NewBox { dst, box_type, args } => {
// Phase 9.78a: Simplified Box creation (temporary until interpreter refactoring)
// Evaluate arguments
let mut arg_values = Vec::new();
for arg_id in args {
let arg_value = self.get_value(*arg_id)?;
arg_values.push(arg_value);
}
// Basic Box creation for common types
let result = match box_type.as_str() {
"StringBox" => {
// Create empty StringBox - in real implementation would use args
let string_box = Box::new(StringBox::new(""));
VMValue::from_nyash_box(string_box)
// Get first argument as string, or empty string
let value = if let Some(arg) = arg_values.first() {
arg.to_string()
} else {
String::new()
};
VMValue::String(value)
},
"IntegerBox" => {
// Get first argument as integer, or 0
let value = if let Some(arg) = arg_values.first() {
arg.as_integer().unwrap_or(0)
} else {
0
};
VMValue::Integer(value)
},
"BoolBox" => {
// Get first argument as bool, or false
let value = if let Some(arg) = arg_values.first() {
arg.as_bool().unwrap_or(false)
} else {
false
};
VMValue::Bool(value)
},
"ArrayBox" => {
// Create empty ArrayBox - in real implementation would use args
// Create empty ArrayBox
let array_box = Box::new(crate::boxes::array::ArrayBox::new());
VMValue::from_nyash_box(array_box)
},
"IntegerBox" => {
// Create IntegerBox with default value
let int_box = Box::new(IntegerBox::new(0));
VMValue::from_nyash_box(int_box)
},
"BoolBox" => {
// Create BoolBox with default value
let bool_box = Box::new(BoolBox::new(false));
VMValue::from_nyash_box(bool_box)
},
_ => {
// For unknown types, create a placeholder string
VMValue::String(format!("NewBox[{}]", box_type))
// For unknown types, create a placeholder
// TODO: Implement proper user-defined Box creation after refactoring
VMValue::String(format!("{}[placeholder]", box_type))
}
};
@ -722,6 +815,13 @@ impl VM {
}
}
/// Phase 9.78a: Unified method dispatch for all Box types
fn call_unified_method(&self, box_value: Box<dyn NyashBox>, method: &str, args: Vec<Box<dyn NyashBox>>) -> Result<Box<dyn NyashBox>, VMError> {
// For now, we use the simplified method dispatch
// In a full implementation, this would check for InstanceBox and dispatch appropriately
self.call_box_method(box_value, method, args)
}
/// Call a method on a Box - simplified version of interpreter method dispatch
fn call_box_method(&self, box_value: Box<dyn NyashBox>, method: &str, _args: Vec<Box<dyn NyashBox>>) -> Result<Box<dyn NyashBox>, VMError> {
// For now, implement basic methods for common box types

View File

@ -11,6 +11,7 @@ use wasm_bindgen::prelude::*;
pub mod box_trait;
pub mod boxes;
pub mod box_factory; // 🏭 Unified Box Factory Architecture (Phase 9.78)
pub mod scope_tracker; // 🎯 Phase 9.78a: Box lifecycle tracking for VM
pub mod stdlib;
pub mod environment;
pub mod tokenizer;

View File

@ -670,75 +670,24 @@ impl MirBuilder {
/// Build new expression: new ClassName(arguments)
fn build_new_expression(&mut self, class: String, arguments: Vec<ASTNode>) -> Result<ValueId, String> {
// Special handling for built-in Box types that have single literal arguments
match class.as_str() {
"IntegerBox" => {
if arguments.len() == 1 {
if let ASTNode::Literal { value: LiteralValue::Integer(n), .. } = &arguments[0] {
// For built-in boxes, just return the value directly
// The VM/interpreter will handle boxing when needed
let dst = self.value_gen.next();
self.emit_instruction(MirInstruction::Const {
dst,
value: ConstValue::Integer(*n),
})?;
return Ok(dst);
}
}
}
"StringBox" => {
if arguments.len() == 1 {
if let ASTNode::Literal { value: LiteralValue::String(s), .. } = &arguments[0] {
let dst = self.value_gen.next();
self.emit_instruction(MirInstruction::Const {
dst,
value: ConstValue::String(s.clone()),
})?;
return Ok(dst);
}
}
}
"FloatBox" => {
if arguments.len() == 1 {
if let ASTNode::Literal { value: LiteralValue::Float(f), .. } = &arguments[0] {
let dst = self.value_gen.next();
self.emit_instruction(MirInstruction::Const {
dst,
value: ConstValue::Float(*f),
})?;
return Ok(dst);
}
}
}
"BoolBox" => {
if arguments.len() == 1 {
if let ASTNode::Literal { value: LiteralValue::Bool(b), .. } = &arguments[0] {
let dst = self.value_gen.next();
self.emit_instruction(MirInstruction::Const {
dst,
value: ConstValue::Bool(*b),
})?;
return Ok(dst);
}
}
}
_ => {}
// Phase 9.78a: Unified Box creation using NewBox instruction
// First, evaluate all arguments to get their ValueIds
let mut arg_values = Vec::new();
for arg in arguments {
let arg_value = self.build_expression(arg)?;
arg_values.push(arg_value);
}
// For other classes, use the original implementation
// Generate the destination ValueId
let dst = self.value_gen.next();
// For now, create a "box type" value representing the class
let type_value = self.value_gen.next();
self.emit_instruction(MirInstruction::Const {
dst: type_value,
value: ConstValue::String(class),
})?;
// Create the reference using RefNew
self.emit_instruction(MirInstruction::RefNew {
// Emit NewBox instruction for all Box types
// VM will handle optimization for basic types internally
self.emit_instruction(MirInstruction::NewBox {
dst,
box_val: type_value,
box_type: class,
args: arg_values,
})?;
Ok(dst)

73
src/scope_tracker.rs Normal file
View File

@ -0,0 +1,73 @@
/*!
* ScopeTracker - Track Box instances for proper lifecycle management
*
* Phase 9.78a: Unified Box lifecycle management for VM
*/
use std::sync::Arc;
use crate::box_trait::NyashBox;
/// Tracks Box instances created in different scopes for proper fini calls
pub struct ScopeTracker {
/// Stack of scopes, each containing Boxes created in that scope
scopes: Vec<Vec<Arc<dyn NyashBox>>>,
}
impl ScopeTracker {
/// Create a new scope tracker
pub fn new() -> Self {
Self {
scopes: vec![Vec::new()], // Start with one root scope
}
}
/// Enter a new scope
pub fn push_scope(&mut self) {
self.scopes.push(Vec::new());
}
/// Exit current scope and call fini on all Boxes created in it
pub fn pop_scope(&mut self) {
if let Some(scope) = self.scopes.pop() {
// Call fini in reverse order of creation
for arc_box in scope.into_iter().rev() {
// For now, fini handling is simplified
// In a full implementation, we would check if the Box has a fini method
// and call it appropriately
// TODO: Implement proper fini dispatch
let _ = arc_box; // Suppress unused warning
}
}
// Ensure we always have at least one scope
if self.scopes.is_empty() {
self.scopes.push(Vec::new());
}
}
/// Register a Box in the current scope
pub fn register_box(&mut self, nyash_box: Arc<dyn NyashBox>) {
if let Some(current_scope) = self.scopes.last_mut() {
current_scope.push(nyash_box);
}
}
/// Clear all scopes (used when resetting VM state)
pub fn clear(&mut self) {
// Pop all scopes and call fini
while self.scopes.len() > 1 {
self.pop_scope();
}
// Clear the root scope
if let Some(root_scope) = self.scopes.first_mut() {
root_scope.clear();
}
}
}
impl Default for ScopeTracker {
fn default() -> Self {
Self::new()
}
}