🏗️ 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:
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
73
src/scope_tracker.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user