//! Minimal NyashRuntime skeleton shared by interpreter and VM //! //! Focused on dependency inversion: core models + runtime services, //! while execution strategies live in interpreter/VM layers. use std::collections::HashMap; use std::sync::{Arc, Mutex, RwLock}; use crate::core::model::BoxDeclaration; use crate::box_factory::{UnifiedBoxRegistry, BoxFactory}; use crate::box_factory::builtin::{BuiltinBoxFactory, BuiltinGroups}; #[cfg(feature = "plugins")] use crate::box_factory::plugin::PluginBoxFactory; /// Core runtime container for executing Nyash programs pub struct NyashRuntime { /// Unified registry that can create any Box type pub box_registry: Arc>, /// User-defined box declarations collected from source pub box_declarations: Arc>>, /// GC hooks (switchable runtime). Default is no-op. pub gc: Arc, /// Optional scheduler (single-thread by default is fine) pub scheduler: Option>, } impl NyashRuntime { /// Create a new runtime with defaults pub fn new() -> Self { Self { box_registry: create_default_registry(), box_declarations: Arc::new(RwLock::new(HashMap::new())), gc: Arc::new(crate::runtime::gc::NullGc), scheduler: Some(Arc::new(crate::runtime::scheduler::SingleThreadScheduler::new())), } } } /// Builder for NyashRuntime allowing DI without globals (future-proof) pub struct NyashRuntimeBuilder { box_registry: Option>>, box_declarations: Option>>>, builtin_groups: Option, gc: Option>, scheduler: Option>, } impl NyashRuntimeBuilder { pub fn new() -> Self { Self { box_registry: None, box_declarations: None, builtin_groups: None, gc: None, scheduler: None } } /// Inject a BoxFactory implementation directly into a private registry pub fn with_factory(mut self, factory: Arc) -> Self { let registry = self.box_registry.take().unwrap_or_else(|| create_default_registry()); if let Ok(mut reg) = registry.lock() { reg.register(factory); } self.box_registry = Some(registry); self } pub fn with_box_declarations( mut self, decls: Arc>>, ) -> Self { self.box_declarations = Some(decls); self } pub fn build(self) -> NyashRuntime { let registry = match self.box_registry { Some(reg) => reg, None => match self.builtin_groups { Some(groups) => create_registry_with_groups(groups), None => create_default_registry(), } }; NyashRuntime { box_registry: registry, box_declarations: self.box_declarations.unwrap_or_else(|| Arc::new(RwLock::new(HashMap::new()))), gc: self.gc.unwrap_or_else(|| Arc::new(crate::runtime::gc::NullGc)), scheduler: Some(self.scheduler.unwrap_or_else(|| Arc::new(crate::runtime::scheduler::SingleThreadScheduler::new()))), } } } fn create_default_registry() -> Arc> { create_registry_with_groups(BuiltinGroups::default()) } fn create_registry_with_groups(groups: BuiltinGroups) -> Arc> { let mut registry = UnifiedBoxRegistry::new(); // Optional: disable builtin boxes entirely to flush out conflicts let disable_builtins = std::env::var("NYASH_DISABLE_BUILTINS").ok().as_deref() == Some("1"); if !disable_builtins { registry.register(Arc::new(BuiltinBoxFactory::new_with_groups(groups))); } else { eprintln!("[UnifiedRegistry] Builtin boxes disabled via NYASH_DISABLE_BUILTINS=1"); } #[cfg(feature = "plugins")] { registry.register(Arc::new(PluginBoxFactory::new())); } Arc::new(Mutex::new(registry)) } impl NyashRuntimeBuilder { /// Configure which builtin groups are registered in the registry. /// If a custom box_registry is already provided, this setting is ignored. pub fn with_builtin_groups(mut self, groups: BuiltinGroups) -> Self { self.builtin_groups = Some(groups); self } /// Inject custom GC hooks (switchable runtime). Default is no-op. pub fn with_gc_hooks(mut self, gc: Arc) -> Self { self.gc = Some(gc); self } /// Convenience: use CountingGc for development metrics pub fn with_counting_gc(mut self) -> Self { let gc = Arc::new(crate::runtime::gc::CountingGc::new()); self.gc = Some(gc); self } /// Inject a custom scheduler implementation pub fn with_scheduler(mut self, sched: Arc) -> Self { self.scheduler = Some(sched); self } /// Convenience: use SingleThreadScheduler pub fn with_single_thread_scheduler(mut self) -> Self { self.scheduler = Some(Arc::new(crate::runtime::scheduler::SingleThreadScheduler::new())); self } }