feat: Unified registry and major code cleanup by ChatGPT5

- Unified Box Registry: Replaced 600+ line match statement with clean factory pattern
- Code cleanup: Removed unused imports, variables, and dead code
- Import fixes: Fixed RangeBox, NullBox, MapBox imports
- Transport Debug: Added Debug trait implementation for Transport interface
- WASM build: Successfully tested with wasm_playground preset ready for integration
- Performance: Build time stable, WASM package generated successfully (1.89MB)

This commit represents a major architectural improvement with the unified registry
system now fully operational, reducing code duplication and improving maintainability.

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Moe Charm
2025-08-21 14:28:24 +09:00
parent bf0229c24a
commit 2fc6ce3aa6
14 changed files with 743 additions and 222 deletions

View File

@ -9,8 +9,66 @@ use super::BoxFactory;
use crate::box_trait::{NyashBox, StringBox, IntegerBox, BoolBox};
use crate::interpreter::RuntimeError;
use crate::boxes::*;
use crate::method_box::MethodBox;
use crate::boxes::p2p_box::TransportKind;
use crate::boxes::math_box::RangeBox;
use std::collections::HashMap;
/// Group switches to control which builtin types are registered
#[derive(Debug, Clone, Copy)]
pub struct BuiltinGroups {
pub basic: bool, // String, Integer, Bool, Float, Null
pub container: bool, // Array, Map, Result, Buffer
pub utility: bool, // Math, Random, Time, Debug
pub io: bool, // Console, Sound
pub network: bool, // Socket, HTTP*
pub text: bool, // Regex, JSON
pub misc: bool, // Stream, Range, Method, Intent, Error
pub native: bool, // DateTime, Timer, Egui (cfg-gated)
pub wasm: bool, // Web* (cfg-gated)
}
impl Default for BuiltinGroups {
fn default() -> Self {
Self {
basic: true,
container: true,
utility: true,
io: true,
network: true,
text: true,
misc: true,
native: true,
wasm: true,
}
}
}
impl BuiltinGroups {
/// Native full preset (default): all groups enabled
pub fn native_full() -> Self { Self::default() }
/// Native minimal preset: disable network-related boxes
pub fn native_minimal() -> Self {
Self { network: false, ..Self::default() }
}
/// WASM playground preset: enable core features, disable native/network/io
/// - native: false (no DateTimeBox/TimerBox/Egui)
/// - io: false (no ConsoleBox/SoundBox)
/// - network: false (no Socket/HTTP/P2P)
/// - wasm: true (enable Web* boxes)
pub fn wasm_playground() -> Self {
Self {
native: false,
io: false,
network: false,
wasm: true,
..Self::default()
}
}
}
type BoxCreator = Box<dyn Fn(&[Box<dyn NyashBox>]) -> Result<Box<dyn NyashBox>, RuntimeError> + Send + Sync>;
/// Factory for all built-in Box types
@ -20,22 +78,33 @@ pub struct BuiltinBoxFactory {
}
impl BuiltinBoxFactory {
/// Create a new factory with all built-in types registered
/// Create a new factory with default (all) groups registered
pub fn new() -> Self {
let mut factory = Self {
creators: HashMap::new(),
};
// Register all built-in Box types
factory.register_basic_types();
factory.register_container_types();
factory.register_utility_types();
factory.register_io_types();
Self::new_with_groups(BuiltinGroups::default())
}
/// Create a new factory with group-based registration control
pub fn new_with_groups(groups: BuiltinGroups) -> Self {
let mut factory = Self { creators: HashMap::new() };
if groups.basic { factory.register_basic_types(); }
if groups.container { factory.register_container_types(); }
if groups.utility { factory.register_utility_types(); }
if groups.io { factory.register_io_types(); }
if groups.network { factory.register_network_types(); }
if groups.text { factory.register_text_types(); }
if groups.misc { factory.register_misc_types(); }
// Platform-specific sets
#[cfg(not(target_arch = "wasm32"))]
factory.register_native_types();
{
if groups.native { factory.register_native_types(); }
}
#[cfg(target_arch = "wasm32")]
factory.register_wasm_types();
{
if groups.wasm { factory.register_wasm_types(); }
}
factory
}
@ -140,6 +209,16 @@ impl BuiltinBoxFactory {
Ok(Box::new(MapBox::new()))
});
// BufferBox
self.register("BufferBox", |args| {
if !args.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("BufferBox constructor expects 0 arguments, got {}", args.len()),
});
}
Ok(Box::new(BufferBox::new()))
});
// ResultBox
self.register("ResultBox", |args| {
if args.len() != 1 {
@ -217,6 +296,183 @@ impl BuiltinBoxFactory {
Ok(Box::new(SoundBox::new()))
});
}
/// Register networking-related types (sockets, HTTP)
fn register_network_types(&mut self) {
// SocketBox
self.register("SocketBox", |args| {
if !args.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("SocketBox constructor expects 0 arguments, got {}", args.len()),
});
}
Ok(Box::new(SocketBox::new()))
});
// HTTPClientBox
self.register("HTTPClientBox", |args| {
if !args.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("HTTPClientBox constructor expects 0 arguments, got {}", args.len()),
});
}
Ok(Box::new(HttpClientBox::new()))
});
// HTTPServerBox
self.register("HTTPServerBox", |args| {
if !args.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("HTTPServerBox constructor expects 0 arguments, got {}", args.len()),
});
}
Ok(Box::new(HTTPServerBox::new()))
});
// HTTPRequestBox
self.register("HTTPRequestBox", |args| {
if !args.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("HTTPRequestBox constructor expects 0 arguments, got {}", args.len()),
});
}
Ok(Box::new(HTTPRequestBox::new()))
});
// HTTPResponseBox
self.register("HTTPResponseBox", |args| {
if !args.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("HTTPResponseBox constructor expects 0 arguments, got {}", args.len()),
});
}
Ok(Box::new(HTTPResponseBox::new()))
});
// P2PBox
self.register("P2PBox", |args| {
if args.len() != 2 {
return Err(RuntimeError::InvalidOperation {
message: format!("P2PBox constructor expects 2 arguments (node_id, transport_type), got {}", args.len()),
});
}
let node_id = args[0].to_string_box().value;
let transport_str = args[1].to_string_box().value;
let transport_kind = transport_str.parse::<TransportKind>()
.map_err(|e| RuntimeError::InvalidOperation { message: e })?;
Ok(Box::new(P2PBox::new(node_id, transport_kind)))
});
}
/// Register text/format related types (Regex, JSON)
fn register_text_types(&mut self) {
// RegexBox
self.register("RegexBox", |args| {
if args.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("RegexBox constructor expects 1 argument, got {}", args.len()),
});
}
let pattern = args[0].to_string_box().value;
match RegexBox::new(&pattern) {
Ok(regex_box) => Ok(Box::new(regex_box)),
Err(e) => Err(RuntimeError::InvalidOperation { message: format!("Invalid regex pattern: {}", e) }),
}
});
// JSONBox
self.register("JSONBox", |args| {
if args.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("JSONBox constructor expects 1 argument, got {}", args.len()),
});
}
let json_str = args[0].to_string_box().value;
match JSONBox::from_str(&json_str) {
Ok(json_box) => Ok(Box::new(json_box)),
Err(e) => Err(RuntimeError::InvalidOperation { message: format!("Invalid JSON: {}", e) }),
}
});
}
/// Register various utility types not covered elsewhere
fn register_misc_types(&mut self) {
// StreamBox
self.register("StreamBox", |args| {
if !args.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("StreamBox constructor expects 0 arguments, got {}", args.len()),
});
}
Ok(Box::new(StreamBox::new()))
});
// TimerBox (native only)
#[cfg(not(target_arch = "wasm32"))]
{
self.register("TimerBox", |args| {
if !args.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("TimerBox constructor expects 0 arguments, got {}", args.len()),
});
}
Ok(Box::new(TimerBox::new()))
});
}
// RangeBox
self.register("RangeBox", |args| {
if args.len() < 2 || args.len() > 3 {
return Err(RuntimeError::InvalidOperation {
message: format!("RangeBox constructor expects 2-3 arguments, got {}", args.len()),
});
}
let start = args[0].to_string_box().value.parse::<i64>().map_err(|_| RuntimeError::TypeError { message: "RangeBox constructor requires integer arguments".to_string() })?;
let end = args[1].to_string_box().value.parse::<i64>().map_err(|_| RuntimeError::TypeError { message: "RangeBox constructor requires integer arguments".to_string() })?;
let step = if args.len() == 3 {
args[2].to_string_box().value.parse::<i64>().map_err(|_| RuntimeError::TypeError { message: "RangeBox constructor requires integer arguments".to_string() })?
} else { 1 };
Ok(Box::new(RangeBox::new(start, end, step)))
});
// MethodBox
self.register("MethodBox", |args| {
if args.len() != 2 {
return Err(RuntimeError::InvalidOperation {
message: format!("MethodBox constructor expects 2 arguments (instance, method_name), got {}", args.len()),
});
}
let instance = args[0].clone_box();
let method_name = args[1].to_string_box().value;
Ok(Box::new(MethodBox::new(instance, method_name)))
});
// IntentBox
self.register("IntentBox", |args| {
if args.len() != 2 {
return Err(RuntimeError::InvalidOperation {
message: format!("IntentBox constructor expects 2 arguments (name, payload), got {}", args.len()),
});
}
let name = args[0].to_string_box().value;
// Try parse payload as JSON, fallback to string
let payload_str = args[1].to_string_box().value;
let payload = match serde_json::from_str::<serde_json::Value>(&payload_str) {
Ok(json) => json,
Err(_) => serde_json::Value::String(payload_str),
};
Ok(Box::new(IntentBox::new(name, payload)))
});
// ErrorBox (Exception)
self.register("ErrorBox", |args| {
let message = match args.get(0) {
Some(arg) => arg.to_string_box().value,
None => String::new(),
};
Ok(Box::new(crate::exception_box::ErrorBox::new(&message)))
});
}
/// Register native-only types
#[cfg(not(target_arch = "wasm32"))]
@ -264,8 +520,38 @@ impl BuiltinBoxFactory {
})
}
});
// Additional WASM types can be registered here
// WebConsoleBox
self.register("WebConsoleBox", |args| {
if args.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("WebConsoleBox constructor expects 1 argument (element_id), got {}", args.len()),
});
}
if let Some(id_str) = args[0].as_any().downcast_ref::<StringBox>() {
Ok(Box::new(crate::boxes::WebConsoleBox::new(id_str.value.clone())))
} else {
Err(RuntimeError::TypeError {
message: "WebConsoleBox constructor requires string element_id argument".to_string(),
})
}
});
// WebCanvasBox
self.register("WebCanvasBox", |args| {
if args.len() != 3 {
return Err(RuntimeError::InvalidOperation {
message: format!("WebCanvasBox constructor expects 3 arguments (canvas_id, width, height), got {}", args.len()),
});
}
let canvas_id = args[0].to_string_box().value;
let width = args[1].to_string_box().value.parse::<u32>()
.map_err(|_| RuntimeError::TypeError { message: "WebCanvasBox width must be integer".to_string() })?;
let height = args[2].to_string_box().value.parse::<u32>()
.map_err(|_| RuntimeError::TypeError { message: "WebCanvasBox height must be integer".to_string() })?;
Ok(Box::new(crate::boxes::WebCanvasBox::new(canvas_id, width, height)))
});
}
/// Register a Box creator function
@ -305,4 +591,4 @@ macro_rules! register_builtins {
$factory.register($box_name, $creator_fn);
)*
};
}
}