diff --git a/projects/nyash-wasm/pkg/README.md b/projects/nyash-wasm/pkg/README.md index 9f453778..34b3a974 100644 --- a/projects/nyash-wasm/pkg/README.md +++ b/projects/nyash-wasm/pkg/README.md @@ -1,180 +1,305 @@ # ๐Ÿฑ Nyash Programming Language +**Next-Generation Browser-Native Programming Experience** -**Everything is Box** - Revolutionary Programming Language +*[๐Ÿ‡ฏ๐Ÿ‡ต ๆ—ฅๆœฌ่ชž็‰ˆใฏใ“ใกใ‚‰ / Japanese Version](README.ja.md)* [![Build Status](https://img.shields.io/badge/Build-Passing-brightgreen.svg)](#) [![Everything is Box](https://img.shields.io/badge/Philosophy-Everything%20is%20Box-blue.svg)](#philosophy) [![WebAssembly](https://img.shields.io/badge/WebAssembly-Ready-orange.svg)](#webassembly) +[![Try Now](https://img.shields.io/badge/Try%20Now-Browser%20Playground-ff6b6b.svg)](projects/nyash-wasm/nyash_playground.html) [![MIT License](https://img.shields.io/badge/License-MIT-green.svg)](#license) -## โœจ Key Features - -- **Everything is Box Philosophy**: Every value is a unified Box object -- **WebAssembly Ready**: Run natively in browsers with zero setup -- **Web Integration**: Control HTML5 Canvas, DOM elements directly from code -- **Self-Hosting**: Written in itself using revolutionary Box architecture -- **Modern Syntax**: Clean, expressive syntax with powerful abstractions - -## ๐Ÿš€ Quick Start - -### Try in Browser (No Installation Required!) - -Open [Nyash Playground](projects/nyash-wasm/nyash_playground.html) in your browser and start coding immediately! - -### Local Development - -```bash -# Clone the repository -git clone https://github.com/user/nyash.git -cd nyash - -# Build with Cargo -cargo build --release - -# Run your first program -./target/release/nyash examples/hello_world.nyash -``` - -## ๐Ÿ’ก Philosophy: Everything is Box - -Nyash revolutionizes programming by treating **everything** as a Box: - -```nyash -// Traditional languages: different types, complex syntax -// Nyash: unified Box approach - -greeting = new StringBox("Hello!") // Text is a Box -number = new IntegerBox(42) // Numbers are Boxes -display = new WebDisplayBox("output") // Even web elements are Boxes! - -// Everything works the same way -display.print(greeting.toString()) -display.print("The answer is: " + number) -``` - -## ๐ŸŽฎ Examples - -### Hello World -```nyash -print("๐Ÿฑ Hello, Nyash World!") -greeting = new StringBox("Welcome to Everything is Box!") -print(greeting.toString()) -``` - -### Web Canvas Graphics -```nyash -canvas = new WebCanvasBox("my-canvas", 400, 300) -canvas.setFillStyle("red") -canvas.fillRect(50, 50, 100, 75) -canvas.fillText("Nyash WebCanvas", 150, 200) -``` - -### Game of Life (Conway) -```nyash -game = new GameOfLifeBox(50, 30) -game.randomize() -loop (game.generation < 100) { - game.step() - game.display() -} -``` - -## ๐Ÿ“š Documentation - -- **[Getting Started](docs/GETTING_STARTED_2025.md)** - Your first steps with Nyash -- **[Language Guide](docs/LANGUAGE_OVERVIEW_2025.md)** - Complete language reference -- **[Technical Architecture](docs/TECHNICAL_ARCHITECTURE_2025.md)** - Deep dive into Box philosophy -- **[Philosophy](PHILOSOPHY.md)** - Everything is Box explained - -## ๐ŸŒ Web Integration - -Nyash provides seamless browser integration: - -```nyash -// Control web page elements directly -display = new WebDisplayBox("output") -display.setHTML("

Generated by Nyash!

") - -// Draw on HTML5 Canvas -canvas = new WebCanvasBox("graphics", 800, 600) -canvas.drawScene() - -// Interactive web apps in pure Nyash -button = new WebButtonBox("click-me") -button.onClick = new MethodBox(app, "handleClick") -``` - -## ๐ŸŽฏ Sample Projects - -Explore our curated examples: - -- **[Hello World](examples/hello_world.nyash)** - Basic syntax and philosophy -- **[Simple Calculator](examples/simple_calculator.nyash)** - Math operations with Boxes -- **[Conway's Game of Life](examples/game_of_life.nyash)** - Complex algorithms made simple -- **[2048 Game](examples/simple_2048.nyash)** - Complete game implementation -- **[Dice RPG](examples/app_dice_rpg.nyash)** - Turn-based battle system -- **[Maze Generator](examples/maze_generator.nyash)** - Procedural generation -- **[Web Canvas Demo](examples/web_canvas_demo.nyash)** - HTML5 Canvas control -- **[Web Display Demo](examples/web_display_demo.nyash)** - DOM manipulation -- **[Text Adventure](examples/text_adventure/)** - Multi-file project structure -- **[Lisp Interpreter](examples/lisp/)** - Meta-programming capabilities - -## โšก Performance & Architecture - -- **Rust Backend**: High-performance native execution -- **WebAssembly Target**: Zero-overhead browser deployment -- **Box Unification**: Simplified memory model, optimized for speed -- **Self-Hosting**: Bootstrap compiler written in Nyash itself - -## ๐Ÿ›  Building from Source - -### Prerequisites -- Rust 1.70+ -- wasm-pack (for WebAssembly builds) - -### Commands -```bash -# Native build -cargo build --release - -# WebAssembly build -wasm-pack build --target web --out-dir projects/nyash-wasm/pkg - -# Run tests -cargo test - -# Generate documentation -cargo doc --open -``` - -## ๐Ÿค Contributing - -We welcome contributions! Here's how to get started: - -1. **Fork** the repository -2. **Create** a feature branch (`git checkout -b feature/amazing-feature`) -3. **Add** your changes and tests -4. **Ensure** all tests pass (`cargo test`) -5. **Commit** your changes (`git commit -m 'Add amazing feature'`) -6. **Push** to your branch (`git push origin feature/amazing-feature`) -7. **Open** a Pull Request - -See our [Contributing Guidelines](CONTRIBUTING.md) for detailed information. - -## ๐Ÿ“„ License - -This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. - -## ๐ŸŒŸ Why Nyash? - -- **Unified Philosophy**: No more juggling different types and paradigms -- **Web-First**: Built for the modern web development ecosystem -- **Self-Documenting**: Everything is Box makes code naturally readable -- **Performance**: Rust backend ensures native-level speed -- **Innovation**: Revolutionary approach to programming language design - --- -**Everything is Box. Everything is Simple. Everything is Nyash.** ๐Ÿฑ +## ๐Ÿš€ **Try Nyash Right Now!** -[Website](https://nyash-lang.org) โ€ข [Documentation](docs/) โ€ข [Examples](examples/) โ€ข [Community](https://discord.gg/nyash) \ No newline at end of file +**No installation, no setup - just open and code!** + +๐Ÿ‘‰ **[๐ŸŽฎ Launch Nyash Browser Playground](https://moe-charm.github.io/nyash/projects/nyash-wasm/nyash_playground.html)** ๐Ÿ‘ˆ + +Experience features like: +- ๐ŸŽจ **Artist Collaboration Demo** - Multiple Box instances working together +- โšก **Async Computing** - Parallel processing made simple +- ๐ŸŽฎ **Canvas Game Graphics** - Direct browser graphics programming +- ๐Ÿ” **Live Debug Visualization** - See your program's memory in real-time + +--- + +## โœจ **Why Nyash Changes Everything** + +### ๐ŸŽฏ **Memory Safety Revolution** +```nyash +// Traditional languages: manual memory management, crashes, security issues +// Nyash: Everything is Box - automatic, safe, elegant + +static box Main { + init { player, enemies, canvas } + + main() { + me.player = new PlayerBox("Hero", 100) + me.canvas = new WebCanvasBox("game", 800, 600) + + // Memory automatically managed - no crashes, no leaks! + me.player.render(me.canvas) + return "Game running safely!" + } +} +``` + +### ๐ŸŒ **Browser-First Design** +- **Zero Installation**: Runs directly in web browsers via WebAssembly +- **Web APIs Built-in**: Canvas, DOM, storage - all native language features +- **Real-time Collaboration**: Share code instantly, run anywhere +- **Mobile Ready**: Works on phones, tablets, any modern device + +### ๐ŸŽจ **Creative Programming Made Easy** +```nyash +// Create art with code - naturally! +box Artist { + init { name, color } + + paintMasterpiece(canvas) { + canvas.fillCircle(100, 100, 50, me.color) + canvas.fillText("Art by " + me.name, 10, 200, "24px Arial", me.color) + } +} + +// Multiple artists collaborate +picasso = new Artist("Picasso", "red") +monet = new Artist("Monet", "blue") +// Each Box maintains its own state and behavior! +``` + +### โšก **Async Simplicity** +```nyash +// Parallel processing without complexity +nowait future1 = heavyComputation(10000) +nowait future2 = renderGraphics() + +// Do other work while they run... +setupUI() + +// Get results when ready +result1 = await future1 +result2 = await future2 +``` + +--- + +## ๐Ÿ—๏ธ **Revolutionary Architecture** + +### Everything is Box Philosophy +Every value in Nyash is a **Box** - a unified, memory-safe container: + +| Traditional Languages | Nyash | +|----------------------|-------| +| `int x = 42;` | `x = new IntegerBox(42)` | +| `string name = "Hello";` | `name = new StringBox("Hello")` | +| Complex canvas setup | `canvas = new WebCanvasBox("game", 800, 600)` | +| Manual memory management | Automatic Box lifecycle management | + +### Static Box Main Pattern +```nyash +// Clean, predictable program structure +static box Main { + init { database, ui, gameState } // Declare all fields upfront + + main() { + // Initialize in logical order + me.database = new DatabaseBox("save.db") + me.ui = new UIManagerBox() + me.gameState = new GameStateBox() + + // Your program logic here + return runGameLoop() + } +} +``` + +### Visual Debug Integration +```nyash +debug = new DebugBox() +debug.startTracking() + +player = new PlayerBox("Hero") +debug.trackBox(player, "Main Character") + +// Real-time memory visualization in browser! +print(debug.memoryReport()) // Live stats, no debugging hell +``` + +--- + +## ๐ŸŽฎ **Perfect for Creative Coding** + +### Game Development +- **Built-in Canvas API**: Graphics without external libraries +- **Input Handling**: Mouse, keyboard, touch - all native +- **Audio Support**: SoundBox for music and effects +- **Physics Ready**: Mathematical operations optimized + +### Educational Programming +- **Visual Feedback**: See your code's effects immediately +- **Memory Visualization**: Understand how programs work +- **No Setup Barriers**: Students code instantly in browser +- **Progressive Learning**: From simple scripts to complex applications + +### Web Applications +- **Direct DOM Control**: WebDisplayBox manipulates HTML +- **No Framework Needed**: Language handles web interaction natively +- **Real-time Updates**: Changes reflect immediately +- **Cross-Platform**: Same code, everywhere + +--- + +## ๐Ÿ“– **Language Highlights** + +### Clean, Expressive Syntax +```nyash +// Object-oriented programming made natural +box Player { + init { name, health, inventory } + + Player(playerName) { + me.name = playerName + me.health = 100 + me.inventory = new ArrayBox() + } + + takeDamage(amount) { + me.health = me.health - amount + if me.health <= 0 { + me.respawn() + } + } + + respawn() { + me.health = 100 + print(me.name + " respawned!") + } +} +``` + +### Powerful Operators +```nyash +// Natural language operators for clarity +isAlive = health > 0 and not poisoned +canCast = mana >= spellCost or hasItem("Magic Ring") +gameOver = playerDead or timeUp + +// Mathematical operations built-in +distance = sqrt((x2 - x1)^2 + (y2 - y1)^2) +angle = atan2(deltaY, deltaX) +``` + +### Generic Programming +```nyash +// Type-safe generic containers +box Container { + init { value } + + Container(item) { me.value = item } + getValue() { return me.value } +} + +numbers = new Container(42) +texts = new Container("Hello") +``` + +--- + +## ๐Ÿ› ๏ธ **Getting Started** + +### Browser Development (Recommended) +```bash +# 1. Clone repository +git clone https://github.com/moe-charm/nyash.git +cd nyash + +# 2. Build WebAssembly version +cd projects/nyash-wasm +./build.sh + +# 3. Open playground in browser +# Open nyash_playground.html in any modern browser +``` + +### Native Development + +#### Linux/WSL +```bash +# Build native version +cargo build --release + +# Run programs locally +./target/release/nyash program.nyash + +# Try examples +./target/release/nyash test_async_demo.nyash +./target/release/nyash app_dice_rpg.nyash +``` + +#### ๐ŸชŸ Windows (Cross-compile) +```bash +# Install cross-compiler +cargo install cargo-xwin + +# Build Windows executable +cargo xwin build --target x86_64-pc-windows-msvc --release + +# Generated executable (916KB) +target/x86_64-pc-windows-msvc/release/nyash.exe +``` + +--- + +## ๐Ÿค **Contributing** + +Nyash is open source and welcomes contributions! + +- **Issues**: Report bugs, request features +- **Pull Requests**: Code improvements, new examples +- **Documentation**: Help improve guides and examples +- **Community**: Share your Nyash creations! + +## ๐Ÿ“„ **License** + +MIT License - Free for personal and commercial use. + +--- + +## ๐Ÿ”— **Links** + +- **[๐ŸŽฎ Try Now - Browser Playground](https://moe-charm.github.io/nyash/projects/nyash-wasm/nyash_playground.html)** +- **[๐Ÿ“š Documentation](docs/)** +- **[๐ŸŽฏ Examples](examples/)** +- **[๐Ÿ’ฌ Community Discussion](https://github.com/moe-charm/nyash/discussions)** + +## ๐Ÿ‘จโ€๐Ÿ’ป **Creator** + +**Moe Charm** - Programming Language Designer & Developer +- ๐Ÿ™ GitHub: [@moe-charm](https://github.com/moe-charm) +- ๐Ÿฆ Twitter/X: [@CharmNexusCore](https://x.com/CharmNexusCore) +- โ˜• Support Development: [coff.ee/moecharmde6](http://coff.ee/moecharmde6) + +*Creating innovative programming languages with AI assistance and dedication ๐Ÿค–* + +--- + +## ๐Ÿค– **Support the Project** + +Nyash is developed with cutting-edge AI collaboration! + +If you enjoy Nyash and want to support continued development: + +**โ˜• [Support Development](http://coff.ee/moecharmde6)** - Help fuel innovation! + +*Powered by Claude Code - Advanced AI development tools aren't free! ๐Ÿค–* + +Your support helps maintain the project, develop new features, and continue pushing the boundaries of programming language design. Every contribution makes a difference! ๐Ÿ™ + +--- + +*Built with โค๏ธ, ๐Ÿค– Claude Code, and the Everything is Box philosophy* + +**Nyash - Where every value is a Box, and every Box tells a story.** \ No newline at end of file diff --git a/projects/nyash-wasm/pkg/nyash_rust_bg.wasm b/projects/nyash-wasm/pkg/nyash_rust_bg.wasm index 428c7757..3a7f1cd2 100644 Binary files a/projects/nyash-wasm/pkg/nyash_rust_bg.wasm and b/projects/nyash-wasm/pkg/nyash_rust_bg.wasm differ diff --git a/src/box_factory/builtin.rs b/src/box_factory/builtin.rs index 97b7dd36..99698660 100644 --- a/src/box_factory/builtin.rs +++ b/src/box_factory/builtin.rs @@ -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]) -> Result, 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::() + .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::().map_err(|_| RuntimeError::TypeError { message: "RangeBox constructor requires integer arguments".to_string() })?; + let end = args[1].to_string_box().value.parse::().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::().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::(&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::() { + 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::() + .map_err(|_| RuntimeError::TypeError { message: "WebCanvasBox width must be integer".to_string() })?; + let height = args[2].to_string_box().value.parse::() + .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); )* }; -} \ No newline at end of file +} diff --git a/src/boxes/mod.rs b/src/boxes/mod.rs index ce975d89..e2ff6347 100644 --- a/src/boxes/mod.rs +++ b/src/boxes/mod.rs @@ -131,8 +131,7 @@ pub mod http_server_box; // P2P้€šไฟกBox็พค (NEW! - Completely rewritten) pub mod intent_box; -// Temporarily commented out until transport/messaging import issues are fixed -// pub mod p2p_box; +pub mod p2p_box; // null้–ขๆ•ฐใ‚‚ๅ†ใ‚จใ‚ฏใ‚นใƒใƒผใƒˆ pub use null_box::{NullBox, null}; @@ -153,5 +152,4 @@ pub use http_server_box::HTTPServerBox; // P2P้€šไฟกBoxใฎๅ†ใ‚จใ‚ฏใ‚นใƒใƒผใƒˆ pub use intent_box::IntentBox; -// Temporarily commented out until transport/messaging import issues are fixed -// pub use p2p_box::P2PBox; \ No newline at end of file +pub use p2p_box::P2PBox; diff --git a/src/boxes/p2p_box.rs b/src/boxes/p2p_box.rs index 159776b0..63fe7568 100644 --- a/src/boxes/p2p_box.rs +++ b/src/boxes/p2p_box.rs @@ -37,8 +37,7 @@ use crate::box_trait::{NyashBox, StringBox, BoolBox, BoxCore, BoxBase}; use crate::boxes::IntentBox; -use crate::transport::{Transport, InProcessTransport, TransportError}; -use crate::messaging::IntentHandler; +use crate::transport::{Transport, InProcessTransport}; use std::any::Any; use std::sync::RwLock; use std::collections::HashMap; @@ -135,6 +134,7 @@ impl P2PBox { let mut handlers = self.handlers.write().unwrap(); handlers.insert(intent_str, handler); Box::new(BoolBox::new(true)) + } /// ใƒŽใƒผใƒ‰ใŒๅˆฐ้”ๅฏ่ƒฝใ‹ใƒใ‚งใƒƒใ‚ฏ pub fn is_reachable(&self, node_id: Box) -> Box { let node_str = node_id.to_string_box().value; @@ -208,4 +208,4 @@ impl std::fmt::Display for P2PBox { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.fmt_box(f) } -} \ No newline at end of file +} diff --git a/src/interpreter/core.rs b/src/interpreter/core.rs index f240060c..41578d44 100644 --- a/src/interpreter/core.rs +++ b/src/interpreter/core.rs @@ -256,6 +256,33 @@ impl NyashInterpreter { runtime, } } + + /// ใ‚ฐใƒซใƒผใƒ—ๆง‹ๆˆใ‚’ๆŒ‡ๅฎšใ—ใฆๆ–ฐใ—ใ„ใ‚คใƒณใ‚ฟใƒผใƒ—ใƒชใ‚ฟใƒผใ‚’ไฝœๆˆ + pub fn new_with_groups(groups: crate::box_factory::builtin::BuiltinGroups) -> Self { + let shared = SharedState::new(); + + use crate::box_factory::user_defined::UserDefinedBoxFactory; + let udf = Arc::new(UserDefinedBoxFactory::new(shared.clone())); + let runtime = NyashRuntimeBuilder::new() + .with_builtin_groups(groups) + .with_factory(udf) + .build(); + + let mut shared = shared; // ๅฏๅค‰ๅŒ– + shared.box_declarations = runtime.box_declarations.clone(); + + Self { + shared, + local_vars: HashMap::new(), + outbox_vars: HashMap::new(), + control_flow: ControlFlow::None, + current_constructor_context: None, + evaluation_stack: Vec::new(), + invalidated_ids: Arc::new(Mutex::new(HashSet::new())), + stdlib: None, + runtime, + } + } /// ๅ…ฑๆœ‰็Šถๆ…‹ใ‹ใ‚‰ๆ–ฐใ—ใ„ใ‚คใƒณใ‚ฟใƒผใƒ—ใƒชใ‚ฟใƒผใ‚’ไฝœๆˆ๏ผˆ้žๅŒๆœŸๅฎŸ่กŒ็”จ๏ผ‰ pub fn with_shared(shared: SharedState) -> Self { @@ -280,6 +307,31 @@ impl NyashInterpreter { runtime, } } + + /// ๅ…ฑๆœ‰็Šถๆ…‹๏ผ‹ใ‚ฐใƒซใƒผใƒ—ๆง‹ๆˆใ‚’ๆŒ‡ๅฎšใ—ใฆๆ–ฐใ—ใ„ใ‚คใƒณใ‚ฟใƒผใƒ—ใƒชใ‚ฟใƒผใ‚’ไฝœๆˆ๏ผˆ้žๅŒๆœŸๅฎŸ่กŒ็”จ๏ผ‰ + pub fn with_shared_and_groups(shared: SharedState, groups: crate::box_factory::builtin::BuiltinGroups) -> Self { + use crate::box_factory::user_defined::UserDefinedBoxFactory; + let udf = Arc::new(UserDefinedBoxFactory::new(shared.clone())); + let runtime = NyashRuntimeBuilder::new() + .with_builtin_groups(groups) + .with_factory(udf) + .build(); + + let mut shared = shared; // ๅฏๅค‰ๅŒ– + shared.box_declarations = runtime.box_declarations.clone(); + + Self { + shared, + local_vars: HashMap::new(), + outbox_vars: HashMap::new(), + control_flow: ControlFlow::None, + current_constructor_context: None, + evaluation_stack: Vec::new(), + invalidated_ids: Arc::new(Mutex::new(HashSet::new())), + stdlib: None, + runtime, + } + } /// ASTใ‚’ๅฎŸ่กŒ pub fn execute(&mut self, ast: ASTNode) -> Result, RuntimeError> { diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index c05af308..80cf096c 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -7,7 +7,7 @@ // Import all necessary dependencies use crate::ast::{ASTNode, CatchClause}; -use crate::box_trait::{NyashBox, StringBox, IntegerBox, BoolBox, VoidBox, ArrayBox, ResultBox, ErrorBox, BoxCore}; +use crate::box_trait::{NyashBox, StringBox, IntegerBox, BoolBox, VoidBox, ErrorBox, BoxCore}; use crate::boxes::FutureBox; use crate::instance_v2::InstanceBox; use crate::channel_box::ChannelBox; diff --git a/src/interpreter/objects.rs b/src/interpreter/objects.rs index a8ce64f0..d614b6c5 100644 --- a/src/interpreter/objects.rs +++ b/src/interpreter/objects.rs @@ -26,12 +26,32 @@ impl NyashInterpreter { match nyash_args { Ok(args) => { - // Try unified registry - use super::super::runtime::get_global_unified_registry; - let registry = get_global_unified_registry(); + // Handle generics: if user-defined and type arguments provided, specialize declaration + let mut target_class = class.to_string(); + let user_defined_exists = { + let box_decls = self.shared.box_declarations.read().unwrap(); + box_decls.contains_key(class) + }; + if user_defined_exists && !type_arguments.is_empty() { + let generic_decl = { + let box_decls = self.shared.box_declarations.read().unwrap(); + box_decls.get(class).cloned() + }; + if let Some(generic_decl) = generic_decl { + // Validate and specialize + self.validate_generic_arguments(&generic_decl, type_arguments)?; + let specialized = self.specialize_generic_class(&generic_decl, type_arguments)?; + target_class = specialized.name.clone(); + // Insert specialized declaration so registry can create it + let mut box_decls = self.shared.box_declarations.write().unwrap(); + box_decls.insert(target_class.clone(), specialized); + } + } + + // Try unified registry (use interpreter's runtime registry to include user-defined boxes) + let registry = self.runtime.box_registry.clone(); let registry_lock = registry.lock().unwrap(); - - match registry_lock.create_box(class, &args) { + match registry_lock.create_box(&target_class, &args) { Ok(box_instance) => { // Check if this is a user-defined box that needs constructor execution @@ -41,7 +61,7 @@ impl NyashInterpreter { // Check if we have a box declaration for this class let (box_decl_opt, constructor_opt) = { let box_decls = self.shared.box_declarations.read().unwrap(); - if let Some(box_decl) = box_decls.get(class) { + if let Some(box_decl) = box_decls.get(&target_class) { // Find the birth constructor (unified constructor system) let birth_key = format!("birth/{}", arguments.len()); let constructor = box_decl.constructors.get(&birth_key).cloned(); @@ -64,7 +84,7 @@ impl NyashInterpreter { return Ok(box_instance); } else { return Err(RuntimeError::InvalidOperation { - message: format!("No constructor found for {} with {} arguments", class, arguments.len()), + message: format!("No constructor found for {} with {} arguments", target_class, arguments.len()), }); } } @@ -74,19 +94,19 @@ impl NyashInterpreter { return Ok(box_instance); }, Err(e) => { - eprintln!("๐Ÿ” Unified registry failed for {}: {}", class, e); - // Fall through to legacy match statement + // Stop here: use unified registry result as source of truth + return Err(e); } } }, Err(e) => { - eprintln!("๐Ÿ” Argument evaluation failed: {}", e); - // Fall through to legacy match statement which will re-evaluate args + // Argument evaluation failed; propagate error + return Err(e); } } - // ๐Ÿšง Legacy implementation (will be removed in Phase 9.78e) - eprintln!("๐Ÿ” Falling back to legacy match statement for: {}", class); + // Unified registry is authoritative; legacy implementation removed + return Err(RuntimeError::UndefinedClass { name: class.to_string() }); // Try basic type constructors first if let Ok(basic_box) = self.create_basic_box(class, arguments) { @@ -103,7 +123,8 @@ impl NyashInterpreter { unreachable!("Basic type {} should have been handled by create_basic_box()", class); } - /* Basic types are now handled by create_basic_box() - keeping for reference + /* Basic types are now handled by create_basic_box() - keeping for reference */ + /* "IntegerBox" => { // IntegerBoxใฏๅผ•ๆ•ฐ1ๅ€‹๏ผˆๆ•ดๆ•ฐๅ€ค๏ผ‰ใงไฝœๆˆ if arguments.len() != 1 { @@ -195,6 +216,7 @@ impl NyashInterpreter { }); } } + */ "MathBox" => { // MathBoxใฏๅผ•ๆ•ฐใชใ—ใงไฝœๆˆ if !arguments.is_empty() { diff --git a/src/interpreter/objects_basic_constructors.rs b/src/interpreter/objects_basic_constructors.rs index 79fe7d8e..a22370e1 100644 --- a/src/interpreter/objects_basic_constructors.rs +++ b/src/interpreter/objects_basic_constructors.rs @@ -5,8 +5,8 @@ use crate::ast::ASTNode; use crate::box_trait::*; use crate::interpreter::core::{NyashInterpreter as Interpreter, RuntimeError}; use crate::boxes::FloatBox; -use crate::NullBox; -use crate::MapBox; +use crate::boxes::null_box::NullBox; +use crate::boxes::map_box::MapBox; impl Interpreter { /// Create basic type boxes (StringBox, IntegerBox, BoolBox, etc.) @@ -154,4 +154,4 @@ impl Interpreter { } } } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index e51d0d78..947abbe0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,8 @@ // ๐ŸŒ WebAssembly support #[cfg(target_arch = "wasm32")] use wasm_bindgen::prelude::*; +#[cfg(target_arch = "wasm32")] +use crate::box_factory::builtin::BuiltinGroups; pub mod box_trait; pub mod boxes; @@ -109,7 +111,7 @@ impl NyashWasm { console_error_panic_hook::set_once(); // Create interpreter with browser-specific setup - let interpreter = NyashInterpreter::new(); + let interpreter = NyashInterpreter::new_with_groups(BuiltinGroups::wasm_playground()); // Register browser-specific boxes // ConsoleBox is available as a constructor: console = new ConsoleBox() diff --git a/src/runner.rs b/src/runner.rs index ace7b7b8..b02504d7 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -15,7 +15,8 @@ use nyash_rust::{ mir::{MirCompiler, MirPrinter, MirInstruction}, backend::VM, }; -use nyash_rust::runtime::NyashRuntime; +use nyash_rust::runtime::{NyashRuntime, NyashRuntimeBuilder}; +use nyash_rust::box_factory::builtin::BuiltinGroups; use nyash_rust::interpreter::SharedState; use nyash_rust::box_factory::user_defined::UserDefinedBoxFactory; use nyash_rust::core::model::BoxDeclaration as CoreBoxDecl; @@ -226,7 +227,7 @@ impl NyashRunner { eprintln!("๐Ÿ” DEBUG: Creating interpreter..."); // Execute the AST - let mut interpreter = NyashInterpreter::new(); + let mut interpreter = NyashInterpreter::new_with_groups(BuiltinGroups::native_full()); eprintln!("๐Ÿ” DEBUG: Starting execution..."); match interpreter.execute(ast) { Ok(result) => { @@ -321,7 +322,9 @@ impl NyashRunner { // Prepare runtime and collect Box declarations for VM user-defined types let runtime = { - let rt = NyashRuntime::new(); + let rt = NyashRuntimeBuilder::new() + .with_builtin_groups(BuiltinGroups::native_full()) + .build(); self.collect_box_declarations(&ast, &rt); // Register UserDefinedBoxFactory backed by the same declarations let mut shared = SharedState::new(); @@ -643,7 +646,7 @@ impl NyashRunner { let start = std::time::Instant::now(); for _ in 0..self.config.iterations { if let Ok(ast) = NyashParser::parse_from_string(test_code) { - let mut interpreter = NyashInterpreter::new(); + let mut interpreter = NyashInterpreter::new_with_groups(BuiltinGroups::native_full()); let _ = interpreter.execute(ast); } } @@ -866,7 +869,7 @@ fn demo_interpreter_system() { match NyashParser::parse_from_string(simple_code) { Ok(ast) => { - let mut interpreter = NyashInterpreter::new(); + let mut interpreter = NyashInterpreter::new_with_groups(BuiltinGroups::native_full()); match interpreter.execute(ast) { Ok(result) => { println!(" โœ… Result: {}", result.to_string_box().value); @@ -891,7 +894,7 @@ fn demo_interpreter_system() { match NyashParser::parse_from_string(expr_code) { Ok(ast) => { - let mut interpreter = NyashInterpreter::new(); + let mut interpreter = NyashInterpreter::new_with_groups(BuiltinGroups::native_full()); match interpreter.execute(ast) { Ok(result) => { println!(" โœ… Result: {}", result.to_string_box().value); diff --git a/src/runtime/nyash_runtime.rs b/src/runtime/nyash_runtime.rs index 92cd73a9..e12c0525 100644 --- a/src/runtime/nyash_runtime.rs +++ b/src/runtime/nyash_runtime.rs @@ -8,7 +8,7 @@ use std::sync::{Arc, Mutex, RwLock}; use crate::core::model::BoxDeclaration; use crate::box_factory::{UnifiedBoxRegistry, BoxFactory}; -use crate::box_factory::builtin::BuiltinBoxFactory; +use crate::box_factory::builtin::{BuiltinBoxFactory, BuiltinGroups}; #[cfg(feature = "plugins")] use crate::box_factory::plugin::PluginBoxFactory; @@ -34,11 +34,12 @@ impl NyashRuntime { pub struct NyashRuntimeBuilder { box_registry: Option>>, box_declarations: Option>>>, + builtin_groups: Option, } impl NyashRuntimeBuilder { pub fn new() -> Self { - Self { box_registry: None, box_declarations: None } + Self { box_registry: None, box_declarations: None, builtin_groups: None } } /// Inject a BoxFactory implementation directly into a private registry @@ -60,19 +61,40 @@ impl NyashRuntimeBuilder { } 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: self.box_registry.unwrap_or_else(|| create_default_registry()), + box_registry: registry, box_declarations: self.box_declarations.unwrap_or_else(|| Arc::new(RwLock::new(HashMap::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(); - registry.register(Arc::new(BuiltinBoxFactory::new())); + registry.register(Arc::new(BuiltinBoxFactory::new_with_groups(groups))); #[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 + } +} diff --git a/src/transport/inprocess.rs b/src/transport/inprocess.rs index 70ce5050..1a141ae8 100644 --- a/src/transport/inprocess.rs +++ b/src/transport/inprocess.rs @@ -24,6 +24,17 @@ pub struct InProcessTransport { receive_callback: Arc>>>, } +impl std::fmt::Debug for InProcessTransport { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("InProcessTransport") + .field("node_id", &self.node_id) + .field("bus", &"MessageBus") + .field("endpoint", &"BusEndpoint") + .field("receive_callback", &"") + .finish() + } +} + impl InProcessTransport { /// ๆ–ฐใ—ใ„InProcessTransportใ‚’ไฝœๆˆ pub fn new(node_id: String) -> Self { diff --git a/src/transport/mod.rs b/src/transport/mod.rs index 9162770e..58a427c1 100644 --- a/src/transport/mod.rs +++ b/src/transport/mod.rs @@ -34,7 +34,7 @@ pub enum TransportError { } /// Abstract transport trait for different communication methods -pub trait Transport: Send + Sync { +pub trait Transport: Send + Sync + std::fmt::Debug { /// Get the node ID of this transport fn node_id(&self) -> &str;