refactor(vm): StaticBoxRegistry unifies static box management
箱化モジュール化: Phase 173-B の散在した static box 管理を一元化 Before (4箇所に散在): - static_box_decls: HashMap (AST経由のBox宣言) - static_boxes: HashMap (実行時シングルトン) - vm.rs Phase 173-B手動検出コード (~60行) - method.rs static_box_decls.contains_key() 直接参照 After (StaticBoxRegistry箱に統一): - declarations: AST経由のBox宣言を登録 - detected_boxes: MIR関数名から自動検出 (using import対応) - instances: 遅延作成シングルトン - naming utilities: parse/format関数 Benefits: - vm.rs: 63行削減 (Phase 173-B手動コード削除) - 自動検出: using import した static box も対応 - 単一責務: static box lifecycle を1箱に集約 - Fail-Fast: 存在しないBoxへのアクセスは即エラー 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -41,7 +41,7 @@ pub(super) fn try_handle_object_fields(
|
|||||||
// Static box support: if box_val is a string matching a static box name,
|
// Static box support: if box_val is a string matching a static box name,
|
||||||
// resolve it to the singleton instance
|
// resolve it to the singleton instance
|
||||||
let actual_box_val = if let Ok(VMValue::String(ref box_name)) = this.reg_load(box_val) {
|
let actual_box_val = if let Ok(VMValue::String(ref box_name)) = this.reg_load(box_val) {
|
||||||
if this.static_box_decls.contains_key(box_name) {
|
if this.static_box_registry.exists(box_name) {
|
||||||
// Get or create singleton instance
|
// Get or create singleton instance
|
||||||
let instance = this.ensure_static_box_instance(box_name)?;
|
let instance = this.ensure_static_box_instance(box_name)?;
|
||||||
let instance_clone = instance.clone();
|
let instance_clone = instance.clone();
|
||||||
@ -363,7 +363,7 @@ pub(super) fn try_handle_object_fields(
|
|||||||
// Static box support: if box_val is a string matching a static box name,
|
// Static box support: if box_val is a string matching a static box name,
|
||||||
// resolve it to the singleton instance
|
// resolve it to the singleton instance
|
||||||
let actual_box_val = if let Ok(VMValue::String(ref box_name)) = this.reg_load(box_val) {
|
let actual_box_val = if let Ok(VMValue::String(ref box_name)) = this.reg_load(box_val) {
|
||||||
if this.static_box_decls.contains_key(box_name) {
|
if this.static_box_registry.exists(box_name) {
|
||||||
// Get or create singleton instance
|
// Get or create singleton instance
|
||||||
let instance = this.ensure_static_box_instance(box_name)?;
|
let instance = this.ensure_static_box_instance(box_name)?;
|
||||||
let instance_clone = instance.clone();
|
let instance_clone = instance.clone();
|
||||||
|
|||||||
@ -137,7 +137,7 @@ impl MirInterpreter {
|
|||||||
Ok(out)
|
Ok(out)
|
||||||
} else {
|
} else {
|
||||||
// Receiver not provided: try static singleton instance for the box (methodize PoC fallback)
|
// Receiver not provided: try static singleton instance for the box (methodize PoC fallback)
|
||||||
if self.static_box_decls.contains_key(box_name) {
|
if self.static_box_registry.exists(box_name) {
|
||||||
// 🎯 Phase 173-B: Static box methods are in MIR function table
|
// 🎯 Phase 173-B: Static box methods are in MIR function table
|
||||||
// Try calling the MIR function directly (BoxName.method/arity pattern)
|
// Try calling the MIR function directly (BoxName.method/arity pattern)
|
||||||
let func_name = format!("{}.{}/{}", box_name, method, args.len());
|
let func_name = format!("{}.{}/{}", box_name, method, args.len());
|
||||||
|
|||||||
@ -21,8 +21,11 @@ mod exec;
|
|||||||
mod handlers;
|
mod handlers;
|
||||||
mod helpers;
|
mod helpers;
|
||||||
mod method_router;
|
mod method_router;
|
||||||
|
pub mod static_box_registry;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
pub use static_box_registry::StaticBoxRegistry;
|
||||||
|
|
||||||
pub struct MirInterpreter {
|
pub struct MirInterpreter {
|
||||||
pub(super) regs: HashMap<ValueId, VMValue>,
|
pub(super) regs: HashMap<ValueId, VMValue>,
|
||||||
pub(super) mem: HashMap<ValueId, VMValue>,
|
pub(super) mem: HashMap<ValueId, VMValue>,
|
||||||
@ -34,10 +37,8 @@ pub struct MirInterpreter {
|
|||||||
pub(super) last_block: Option<BasicBlockId>,
|
pub(super) last_block: Option<BasicBlockId>,
|
||||||
pub(super) last_inst: Option<MirInstruction>,
|
pub(super) last_inst: Option<MirInstruction>,
|
||||||
pub(super) last_inst_index: Option<usize>,
|
pub(super) last_inst_index: Option<usize>,
|
||||||
// Static box singleton instances (persistent across method calls)
|
// 🎯 Phase 173-B: Unified static box management via StaticBoxRegistry
|
||||||
pub(super) static_boxes: HashMap<String, crate::instance_v2::InstanceBox>,
|
pub(super) static_box_registry: StaticBoxRegistry,
|
||||||
// Static box declarations (metadata for creating instances)
|
|
||||||
pub(super) static_box_decls: HashMap<String, crate::core::model::BoxDeclaration>,
|
|
||||||
// Lightweight dev counters (opt-in print via NYASH_VM_STATS=1)
|
// Lightweight dev counters (opt-in print via NYASH_VM_STATS=1)
|
||||||
pub(super) inst_count: u64,
|
pub(super) inst_count: u64,
|
||||||
pub(super) branch_count: u64,
|
pub(super) branch_count: u64,
|
||||||
@ -58,8 +59,7 @@ impl MirInterpreter {
|
|||||||
last_block: None,
|
last_block: None,
|
||||||
last_inst: None,
|
last_inst: None,
|
||||||
last_inst_index: None,
|
last_inst_index: None,
|
||||||
static_boxes: HashMap::new(),
|
static_box_registry: StaticBoxRegistry::new(),
|
||||||
static_box_decls: HashMap::new(),
|
|
||||||
inst_count: 0,
|
inst_count: 0,
|
||||||
branch_count: 0,
|
branch_count: 0,
|
||||||
compare_count: 0,
|
compare_count: 0,
|
||||||
@ -73,17 +73,26 @@ impl MirInterpreter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Register static box declarations (called from vm.rs during setup)
|
/// Register static box declarations (called from vm.rs during setup)
|
||||||
|
/// Now delegated to StaticBoxRegistry
|
||||||
pub fn register_static_box_decl(
|
pub fn register_static_box_decl(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: String,
|
name: String,
|
||||||
decl: crate::core::model::BoxDeclaration,
|
decl: crate::core::model::BoxDeclaration,
|
||||||
) {
|
) {
|
||||||
self.static_box_decls.insert(name, decl);
|
self.static_box_registry.register_declaration(name, decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if a static box is already registered (Phase 173-B)
|
/// Check if a static box is already registered (Phase 173-B)
|
||||||
|
/// Now delegated to StaticBoxRegistry
|
||||||
pub fn has_static_box_decl(&self, name: &str) -> bool {
|
pub fn has_static_box_decl(&self, name: &str) -> bool {
|
||||||
self.static_box_decls.contains_key(name)
|
self.static_box_registry.exists(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize registry from MIR function names (auto-detect using imports)
|
||||||
|
/// Called from vm.rs after module is loaded
|
||||||
|
pub fn detect_static_boxes_from_functions(&mut self) {
|
||||||
|
self.static_box_registry
|
||||||
|
.detect_from_mir_functions(self.functions.keys());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute a BoxCall with VM's complete semantics (Phase 27-shortterm S-5.2-improved)
|
/// Execute a BoxCall with VM's complete semantics (Phase 27-shortterm S-5.2-improved)
|
||||||
@ -153,60 +162,23 @@ impl MirInterpreter {
|
|||||||
|
|
||||||
/// Ensure static box singleton instance exists, create if not
|
/// Ensure static box singleton instance exists, create if not
|
||||||
/// Returns mutable reference to the singleton instance
|
/// Returns mutable reference to the singleton instance
|
||||||
|
/// Now delegated to StaticBoxRegistry
|
||||||
fn ensure_static_box_instance(
|
fn ensure_static_box_instance(
|
||||||
&mut self,
|
&mut self,
|
||||||
box_name: &str,
|
box_name: &str,
|
||||||
) -> Result<&mut crate::instance_v2::InstanceBox, VMError> {
|
) -> Result<&mut crate::instance_v2::InstanceBox, VMError> {
|
||||||
// Check if instance already exists
|
self.static_box_registry
|
||||||
if !self.static_boxes.contains_key(box_name) {
|
.get_or_create_instance(box_name)
|
||||||
// Get declaration
|
.map_err(|e| VMError::InvalidInstruction(e))
|
||||||
let decl = self
|
|
||||||
.static_box_decls
|
|
||||||
.get(box_name)
|
|
||||||
.ok_or_else(|| {
|
|
||||||
VMError::InvalidInstruction(format!(
|
|
||||||
"static box declaration not found: {}",
|
|
||||||
box_name
|
|
||||||
))
|
|
||||||
})?
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
// Create instance from declaration
|
|
||||||
let instance = crate::instance_v2::InstanceBox::from_declaration(
|
|
||||||
box_name.to_string(),
|
|
||||||
decl.fields.clone(),
|
|
||||||
decl.methods.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
self.static_boxes.insert(box_name.to_string(), instance);
|
|
||||||
|
|
||||||
if std::env::var("NYASH_VM_STATIC_TRACE").ok().as_deref() == Some("1") {
|
|
||||||
eprintln!(
|
|
||||||
"[vm-static] created singleton instance for static box: {}",
|
|
||||||
box_name
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return mutable reference
|
|
||||||
self.static_boxes.get_mut(box_name).ok_or_else(|| {
|
|
||||||
VMError::InvalidInstruction(format!(
|
|
||||||
"static box instance not found after creation: {}",
|
|
||||||
box_name
|
|
||||||
))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if a function name represents a static box method
|
/// Check if a function name represents a static box method
|
||||||
/// Format: "BoxName.method/Arity"
|
/// Format: "BoxName.method/Arity"
|
||||||
|
/// Now uses StaticBoxRegistry naming utilities
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn is_static_box_method(&self, func_name: &str) -> Option<String> {
|
fn is_static_box_method(&self, func_name: &str) -> Option<String> {
|
||||||
if let Some((box_name, _rest)) = func_name.split_once('.') {
|
static_box_registry::naming::extract_box_name(func_name)
|
||||||
if self.static_box_decls.contains_key(box_name) {
|
.filter(|name| self.static_box_registry.exists(name))
|
||||||
return Some(box_name.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute module entry (main) and return boxed result
|
/// Execute module entry (main) and return boxed result
|
||||||
@ -214,6 +186,10 @@ impl MirInterpreter {
|
|||||||
// Snapshot functions for call resolution
|
// Snapshot functions for call resolution
|
||||||
self.functions = module.functions.clone();
|
self.functions = module.functions.clone();
|
||||||
|
|
||||||
|
// 🎯 Phase 173-B: Auto-detect static boxes from MIR function names
|
||||||
|
// This handles using-imported static boxes that aren't in AST
|
||||||
|
self.detect_static_boxes_from_functions();
|
||||||
|
|
||||||
// Determine entry function with sensible fallbacks
|
// Determine entry function with sensible fallbacks
|
||||||
// Priority:
|
// Priority:
|
||||||
// 1) NYASH_ENTRY env (exact), then basename before '/' if provided (e.g., "Main.main/0" → "Main.main")
|
// 1) NYASH_ENTRY env (exact), then basename before '/' if provided (e.g., "Main.main/0" → "Main.main")
|
||||||
|
|||||||
284
src/backend/mir_interpreter/static_box_registry.rs
Normal file
284
src/backend/mir_interpreter/static_box_registry.rs
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
/*!
|
||||||
|
* StaticBoxRegistry - 静的Box管理の一元化箱
|
||||||
|
*
|
||||||
|
* 箱理論の実践:
|
||||||
|
* - 箱にする: static_box_decls + static_boxes + MIR関数検出を1箱に集約
|
||||||
|
* - 境界を作る: 静的Boxの存在証明・シングルトン管理を単一責務に
|
||||||
|
* - Fail-Fast: 存在しないBoxへのアクセスは即座にエラー
|
||||||
|
*
|
||||||
|
* 設計原則:
|
||||||
|
* - MIR関数名から自動検出: "BoxName.method/arity" パターンでusing importも対応
|
||||||
|
* - 遅延シングルトン: 実際にアクセスされるまでインスタンス作成しない
|
||||||
|
* - 明示的登録も可能: AST経由のBoxDeclarationも受け入れ
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
|
use crate::core::model::BoxDeclaration;
|
||||||
|
use crate::instance_v2::InstanceBox;
|
||||||
|
|
||||||
|
/// 静的Box管理の一元化レジストリ
|
||||||
|
///
|
||||||
|
/// Phase 173-B で発生した問題を根本解決:
|
||||||
|
/// - using import された静的Boxが static_box_decls に登録されない問題
|
||||||
|
/// - MIR関数テーブルと static_box_decls の不整合問題
|
||||||
|
pub struct StaticBoxRegistry {
|
||||||
|
/// 明示的に登録されたBoxDeclaration (AST経由)
|
||||||
|
declarations: HashMap<String, BoxDeclaration>,
|
||||||
|
|
||||||
|
/// MIR関数名から検出された静的Box名
|
||||||
|
/// (using import でも自動検出可能)
|
||||||
|
detected_boxes: HashSet<String>,
|
||||||
|
|
||||||
|
/// 実行時シングルトン (遅延作成)
|
||||||
|
instances: HashMap<String, InstanceBox>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MIR関数名のパースユーティリティ
|
||||||
|
pub mod naming {
|
||||||
|
/// "BoxName.method/arity" 形式の関数名をパース
|
||||||
|
/// Returns: Some((box_name, method, arity)) or None
|
||||||
|
pub fn parse_static_method_name(fn_name: &str) -> Option<(String, String, usize)> {
|
||||||
|
// "BoxName.method/arity" or "BoxName.method"
|
||||||
|
let dot_pos = fn_name.find('.')?;
|
||||||
|
let box_name = &fn_name[..dot_pos];
|
||||||
|
let rest = &fn_name[dot_pos + 1..];
|
||||||
|
|
||||||
|
let (method, arity) = if let Some(slash_pos) = rest.find('/') {
|
||||||
|
let method = &rest[..slash_pos];
|
||||||
|
let arity_str = &rest[slash_pos + 1..];
|
||||||
|
let arity = arity_str.parse::<usize>().ok()?;
|
||||||
|
(method.to_string(), arity)
|
||||||
|
} else {
|
||||||
|
(rest.to_string(), 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
Some((box_name.to_string(), method, arity))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 静的Boxメソッド名を生成
|
||||||
|
pub fn static_method_name(box_name: &str, method: &str, arity: usize) -> String {
|
||||||
|
format!("{}.{}/{}", box_name, method, arity)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 関数名からBox名を抽出 (メソッド・arity無視)
|
||||||
|
pub fn extract_box_name(fn_name: &str) -> Option<String> {
|
||||||
|
parse_static_method_name(fn_name).map(|(box_name, _, _)| box_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 除外する組み込みBox名 (静的Boxではない)
|
||||||
|
const BUILTIN_RUNTIME_BOXES: &[&str] = &[
|
||||||
|
"Main",
|
||||||
|
"main",
|
||||||
|
"StringBox",
|
||||||
|
"IntegerBox",
|
||||||
|
"BoolBox",
|
||||||
|
"ArrayBox",
|
||||||
|
"MapBox",
|
||||||
|
"FloatBox",
|
||||||
|
"VoidBox",
|
||||||
|
"NullBox",
|
||||||
|
"ConsoleBox",
|
||||||
|
"MathBox",
|
||||||
|
"FileBox",
|
||||||
|
"NetBox",
|
||||||
|
"CounterBox",
|
||||||
|
];
|
||||||
|
|
||||||
|
impl StaticBoxRegistry {
|
||||||
|
/// 空のレジストリを作成
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
declarations: HashMap::new(),
|
||||||
|
detected_boxes: HashSet::new(),
|
||||||
|
instances: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MIR関数名一覧から静的Boxを自動検出
|
||||||
|
///
|
||||||
|
/// using import された静的Boxも含めて検出可能
|
||||||
|
pub fn detect_from_mir_functions<'a, I>(&mut self, fn_names: I)
|
||||||
|
where
|
||||||
|
I: Iterator<Item = &'a String>,
|
||||||
|
{
|
||||||
|
for fn_name in fn_names {
|
||||||
|
if let Some(box_name) = naming::extract_box_name(fn_name) {
|
||||||
|
// 組み込みランタイムBoxは除外
|
||||||
|
if !BUILTIN_RUNTIME_BOXES.contains(&box_name.as_str()) {
|
||||||
|
self.detected_boxes.insert(box_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if std::env::var("NYASH_STATIC_BOX_REGISTRY_TRACE")
|
||||||
|
.ok()
|
||||||
|
.as_deref()
|
||||||
|
== Some("1")
|
||||||
|
{
|
||||||
|
eprintln!(
|
||||||
|
"[static-box-registry] detected {} static boxes from MIR functions",
|
||||||
|
self.detected_boxes.len()
|
||||||
|
);
|
||||||
|
for name in &self.detected_boxes {
|
||||||
|
eprintln!(" - {}", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// BoxDeclarationを明示的に登録 (AST経由)
|
||||||
|
pub fn register_declaration(&mut self, name: String, decl: BoxDeclaration) {
|
||||||
|
self.declarations.insert(name, decl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 静的Boxが存在するか確認
|
||||||
|
///
|
||||||
|
/// 以下のいずれかで存在とみなす:
|
||||||
|
/// 1. declarations に登録済み
|
||||||
|
/// 2. detected_boxes に検出済み
|
||||||
|
pub fn exists(&self, name: &str) -> bool {
|
||||||
|
self.declarations.contains_key(name) || self.detected_boxes.contains(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// シングルトンインスタンスを取得または作成
|
||||||
|
///
|
||||||
|
/// 遅延作成: 初回アクセス時にのみ作成
|
||||||
|
pub fn get_or_create_instance(&mut self, name: &str) -> Result<&mut InstanceBox, String> {
|
||||||
|
if !self.exists(name) {
|
||||||
|
return Err(format!(
|
||||||
|
"static box '{}' not found in registry (neither declared nor detected)",
|
||||||
|
name
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 既存インスタンスがあればそれを返す
|
||||||
|
if self.instances.contains_key(name) {
|
||||||
|
return Ok(self.instances.get_mut(name).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新規作成
|
||||||
|
let instance = if let Some(decl) = self.declarations.get(name) {
|
||||||
|
// 明示的な宣言がある場合
|
||||||
|
InstanceBox::from_declaration(
|
||||||
|
name.to_string(),
|
||||||
|
decl.fields.clone(),
|
||||||
|
decl.methods.clone(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// MIR関数から検出された場合 (宣言なし)
|
||||||
|
// 最小限のInstanceBoxを作成 (メソッドはMIR関数テーブルにある)
|
||||||
|
InstanceBox::from_declaration(name.to_string(), vec![], HashMap::new())
|
||||||
|
};
|
||||||
|
|
||||||
|
if std::env::var("NYASH_STATIC_BOX_REGISTRY_TRACE")
|
||||||
|
.ok()
|
||||||
|
.as_deref()
|
||||||
|
== Some("1")
|
||||||
|
{
|
||||||
|
eprintln!(
|
||||||
|
"[static-box-registry] created singleton instance for '{}'",
|
||||||
|
name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.instances.insert(name.to_string(), instance);
|
||||||
|
Ok(self.instances.get_mut(name).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// シングルトンインスタンスが既に作成済みか確認
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn has_instance(&self, name: &str) -> bool {
|
||||||
|
self.instances.contains_key(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 登録済み/検出済みの静的Box名一覧
|
||||||
|
pub fn all_box_names(&self) -> impl Iterator<Item = &String> {
|
||||||
|
self.declarations
|
||||||
|
.keys()
|
||||||
|
.chain(self.detected_boxes.iter())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// declarations への直接アクセス (既存コードとの互換性)
|
||||||
|
pub fn declarations(&self) -> &HashMap<String, BoxDeclaration> {
|
||||||
|
&self.declarations
|
||||||
|
}
|
||||||
|
|
||||||
|
/// detected_boxes への直接アクセス
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn detected_boxes(&self) -> &HashSet<String> {
|
||||||
|
&self.detected_boxes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for StaticBoxRegistry {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_static_method_name() {
|
||||||
|
assert_eq!(
|
||||||
|
naming::parse_static_method_name("JsonParserBox.parse/1"),
|
||||||
|
Some(("JsonParserBox".to_string(), "parse".to_string(), 1))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
naming::parse_static_method_name("MyBox.toString/0"),
|
||||||
|
Some(("MyBox".to_string(), "toString".to_string(), 0))
|
||||||
|
);
|
||||||
|
assert_eq!(naming::parse_static_method_name("main"), None);
|
||||||
|
assert_eq!(naming::parse_static_method_name("no_dot"), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_static_method_name() {
|
||||||
|
assert_eq!(
|
||||||
|
naming::static_method_name("JsonParserBox", "parse", 1),
|
||||||
|
"JsonParserBox.parse/1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_detect_from_mir_functions() {
|
||||||
|
let mut registry = StaticBoxRegistry::new();
|
||||||
|
let fn_names = vec![
|
||||||
|
"JsonParserBox.parse/1".to_string(),
|
||||||
|
"JsonParserBox.toString/0".to_string(),
|
||||||
|
"ProgramJSONBox.get/1".to_string(),
|
||||||
|
"Main.main/0".to_string(), // 除外される
|
||||||
|
"StringBox.length/0".to_string(), // 除外される
|
||||||
|
];
|
||||||
|
|
||||||
|
registry.detect_from_mir_functions(fn_names.iter());
|
||||||
|
|
||||||
|
assert!(registry.exists("JsonParserBox"));
|
||||||
|
assert!(registry.exists("ProgramJSONBox"));
|
||||||
|
assert!(!registry.exists("Main")); // 除外
|
||||||
|
assert!(!registry.exists("StringBox")); // 除外
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_or_create_instance() {
|
||||||
|
let mut registry = StaticBoxRegistry::new();
|
||||||
|
registry.detected_boxes.insert("TestBox".to_string());
|
||||||
|
|
||||||
|
let result = registry.get_or_create_instance("TestBox");
|
||||||
|
assert!(result.is_ok());
|
||||||
|
|
||||||
|
// 2回目も同じインスタンスを返す
|
||||||
|
assert!(registry.has_instance("TestBox"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_nonexistent_box_error() {
|
||||||
|
let mut registry = StaticBoxRegistry::new();
|
||||||
|
let result = registry.get_or_create_instance("NonExistent");
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert!(result.unwrap_err().contains("not found in registry"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -496,74 +496,11 @@ impl NyashRunner {
|
|||||||
use crate::backend::MirInterpreter;
|
use crate::backend::MirInterpreter;
|
||||||
let mut vm = MirInterpreter::new();
|
let mut vm = MirInterpreter::new();
|
||||||
|
|
||||||
// Register static box declarations for singleton persistence
|
// Register static box declarations for singleton persistence (AST-based)
|
||||||
for (name, decl) in static_box_decls {
|
for (name, decl) in static_box_decls {
|
||||||
vm.register_static_box_decl(name, decl);
|
vm.register_static_box_decl(name, decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🎯 Phase 173-B: Register using-imported static boxes from MIR function names
|
|
||||||
// Extract box names from MIR function patterns like "BoxName.method/arity"
|
|
||||||
// This enables VM singleton creation for using-imported static boxes
|
|
||||||
{
|
|
||||||
use std::collections::HashSet;
|
|
||||||
let mut imported_boxes: HashSet<String> = HashSet::new();
|
|
||||||
|
|
||||||
for fn_name in module_vm.functions.keys() {
|
|
||||||
// Parse "BoxName.method/arity" pattern
|
|
||||||
if let Some(dot_pos) = fn_name.find('.') {
|
|
||||||
let box_name = &fn_name[..dot_pos];
|
|
||||||
// Skip known non-static boxes (runtime data boxes)
|
|
||||||
if !matches!(
|
|
||||||
box_name,
|
|
||||||
"Main"
|
|
||||||
| "main"
|
|
||||||
| "StringBox"
|
|
||||||
| "IntegerBox"
|
|
||||||
| "BoolBox"
|
|
||||||
| "ArrayBox"
|
|
||||||
| "MapBox"
|
|
||||||
| "FileBox"
|
|
||||||
| "NetBox"
|
|
||||||
) {
|
|
||||||
imported_boxes.insert(box_name.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register any boxes not already in static_box_decls
|
|
||||||
for box_name in imported_boxes {
|
|
||||||
if !vm.has_static_box_decl(&box_name) {
|
|
||||||
// Create minimal BoxDeclaration for using-imported boxes
|
|
||||||
// VM only needs the name for singleton creation
|
|
||||||
let decl = crate::core::model::BoxDeclaration {
|
|
||||||
name: box_name.clone(),
|
|
||||||
fields: Vec::new(),
|
|
||||||
public_fields: Vec::new(),
|
|
||||||
private_fields: Vec::new(),
|
|
||||||
methods: std::collections::HashMap::new(),
|
|
||||||
constructors: std::collections::HashMap::new(),
|
|
||||||
init_fields: Vec::new(),
|
|
||||||
weak_fields: Vec::new(),
|
|
||||||
is_interface: false,
|
|
||||||
extends: Vec::new(),
|
|
||||||
implements: Vec::new(),
|
|
||||||
type_parameters: Vec::new(),
|
|
||||||
};
|
|
||||||
if std::env::var("NYASH_USING_STATIC_BOX_TRACE")
|
|
||||||
.ok()
|
|
||||||
.as_deref()
|
|
||||||
== Some("1")
|
|
||||||
{
|
|
||||||
eprintln!(
|
|
||||||
"[phase173-b] Registering using-imported static box: {}",
|
|
||||||
box_name
|
|
||||||
);
|
|
||||||
}
|
|
||||||
vm.register_static_box_decl(box_name, decl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optional: verify MIR before execution (dev-only)
|
// Optional: verify MIR before execution (dev-only)
|
||||||
if crate::config::env::env_bool("NYASH_VM_VERIFY_MIR") {
|
if crate::config::env::env_bool("NYASH_VM_VERIFY_MIR") {
|
||||||
let ring0 = crate::runtime::ring0::get_global_ring0();
|
let ring0 = crate::runtime::ring0::get_global_ring0();
|
||||||
|
|||||||
Reference in New Issue
Block a user