diff --git a/.gitignore b/.gitignore index 4a9dda16..e8fd3506 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,8 @@ nyash-rust/ # 開発用秘密フォルダ(完全除外) /development/ +/private/ +/private_test/ # Test files *.tmp @@ -118,4 +120,7 @@ local_tests/ # Font files (already in assets/) *.ttf -*.otf \ No newline at end of file +*.otf + +# Backup files +/backups/ \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index 65b17b51..127ccc5d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -5,22 +5,21 @@ ## Start Here (必ずここから) - 現在のタスク: docs/development/current/CURRENT_TASK.md - ドキュメントハブ: README.md -- 主軸タスクリスト: docs/development/roadmap/native-plan/copilot_issues.txt +- 🚀 **開発マスタープラン**: docs/development/roadmap/phases/00_MASTER_ROADMAP.md Notes: - ここから先の導線は README.md に集約。Claude Codeくんがこのファイルを上書きしても最低限のリンクは保たれるよ。 -## 🤖 **Claude×Copilot協調開発の主軸** -### 📋 **copilot_issues.txt - 開発の軸となるファイル** -**すべてはここに書いてある!** - Phase順タスク・優先順位・技術詳細 +## 🤖 **Claude×Copilot×ChatGPT協調開発** +### 📋 **開発マスタープラン - 全フェーズの統合ロードマップ** +**すべてはここに書いてある!** → [00_MASTER_ROADMAP.md](docs/development/roadmap/phases/00_MASTER_ROADMAP.md) -- **Phase 8.4**: AST→MIR Lowering完全実装(最優先) -- **Phase 8.5**: MIRダイエット(35命令→20命令) -- **Phase 8.6**: VM性能改善(0.9倍 → 2倍以上) +- **Phase 8.6**: VM性能改善(0.9倍 → 2倍以上)**← 現在ここ** - **Phase 9**: JIT実装 - **Phase 10**: Cranelift JIT(主経路)/ LLVM AOTは後段 +- **Phase 9.8**: BIDレジストリ(プラグイン全バックエンド対応) -**迷ったらcopilot_issues.txtを確認せよ!** +**迷ったらマスタープランを確認せよ!** ## 🏃 開発の基本方針: 80/20ルール - 完璧より進捗 diff --git a/Cargo.toml.backup b/Cargo.toml.backup deleted file mode 100644 index 910107e8..00000000 --- a/Cargo.toml.backup +++ /dev/null @@ -1,171 +0,0 @@ -[package] -name = "nyash-rust" -version = "0.1.0" -edition = "2021" -authors = ["Claude Code "] -description = "Everything is Box in Rust - Ultimate Memory Safe Nyash Implementation" -license = "MIT" -repository = "https://github.com/user/nyash" -keywords = ["language", "interpreter", "box", "memory-safe", "rust"] -categories = ["development-tools::parsing", "interpreters"] - -# Default features - minimal CLI only -[features] -default = ["cli"] -cli = [] -gui = ["dep:egui", "dep:eframe", "dep:egui_extras", "dep:image"] -gui-examples = ["gui"] -all-examples = ["gui-examples"] - -[lib] -name = "nyash_rust" -path = "src/lib.rs" -crate-type = ["cdylib", "rlib"] - -# Main CLI binary - always available -[[bin]] -name = "nyash" -path = "src/main.rs" - -# Examples for development - only available as examples, not bins -[[example]] -name = "gui_simple_notepad" -path = "examples/simple_notepad.rs" -required-features = ["gui-examples"] - -[[example]] -name = "gui_simple_notepad_v2" -path = "examples/simple_notepad_v2.rs" -required-features = ["gui-examples"] - -[[example]] -name = "gui_simple_notepad_ascii" -path = "examples/simple_notepad_ascii.rs" -required-features = ["gui-examples"] - -[[example]] -name = "gui_debug_notepad" -path = "examples/debug_notepad.rs" -required-features = ["gui-examples"] - -[[example]] -name = "gui_nyash_notepad_jp" -path = "examples/nyash_notepad_jp.rs" -required-features = ["gui-examples"] - -[[example]] -name = "gui_nyash_explorer" -path = "examples/nyash_explorer.rs" -required-features = ["gui-examples"] - -[[example]] -name = "gui_nyash_explorer_with_icons" -path = "examples/nyash_explorer_with_icons.rs" -required-features = ["gui-examples"] - -[[example]] -name = "gui_test_icon_extraction" -path = "examples/test_icon_extraction.rs" -required-features = ["gui-examples"] - -[[example]] -name = "gui_visual_node_prototype" -path = "development/egui_research/experiments/visual_node_prototype.rs" -required-features = ["gui-examples"] - - - -[dependencies] -# エラーハンドリング -thiserror = "2.0" -anyhow = "1.0" - -# シリアライゼーション(将来のAST永続化用) -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" - -# コマンドライン(将来の CLI用) -clap = { version = "4.0", features = ["derive"] } - -# 並行処理(GlobalBox用) -lazy_static = "1.5" -once_cell = "1.20" - -# デバッグ・ログ -log = "0.4" -env_logger = "0.11" - -# 日時処理 -chrono = "0.4" - -# HTTP通信(HttpClientBox用) -# reqwest = { version = "0.11", features = ["blocking"] } # Temporarily disabled - -# 正規表現(RegexBox用) -regex = "1.0" - -# WebAssembly対応 -wasm-bindgen = "0.2" -console_error_panic_hook = "0.1" -js-sys = "0.3" - -# WASM backend dependencies (Phase 8) -wabt = "0.10" -wasmtime = "35.0.0" - -# GUI フレームワーク - only when gui feature is enabled -egui = { version = "0.29", optional = true } -eframe = { version = "0.29", default-features = false, features = ["default_fonts", "glow"], optional = true } -egui_extras = { version = "0.29", features = ["image"], optional = true } -image = { version = "0.25", features = ["png", "ico"], optional = true } - -# Windows API -[target.'cfg(windows)'.dependencies] -windows = { version = "0.60", features = [ - "Win32_Foundation", - "Win32_Storage_FileSystem", - "Win32_UI_Shell", - "Win32_UI_WindowsAndMessaging", - "Win32_System_Com", - "Win32_Graphics_Gdi", -] } - -[dependencies.web-sys] -version = "0.3" -features = [ - "console", - "Document", - "Element", - "HtmlElement", - "Window", - "DomTokenList", - "CssStyleDeclaration", - "HtmlCanvasElement", - "CanvasRenderingContext2d", - "ImageData", - "TextMetrics", - "CanvasGradient", - "CanvasPattern", - "Path2d", -] - -[dev-dependencies] -# テスト・ベンチマークツール -criterion = "0.5" - -# Benchmark configuration (will be added later) -# [[bench]] -# name = "box_performance" -# harness = false - -[profile.release] -# 最適化設定 -opt-level = 3 -lto = true -codegen-units = 1 -panic = "abort" - -[profile.dev] -# 開発用設定 -opt-level = 0 -debug = true diff --git a/build_error.txt b/build_error.txt deleted file mode 100644 index b2cc8735..00000000 --- a/build_error.txt +++ /dev/null @@ -1,247 +0,0 @@ - Compiling nyash-rust v0.1.0 (/mnt/c/git/nyash-project/nyash) -error: implementation is not supported in `trait`s or `impl`s - --> src/runtime/plugin_loader_v2.rs:235:5 - | -235 | impl PluginLoaderV2 { - | ^^^^^^^^^^^^^^^^^^^ - | - = help: consider moving the implementation out to a nearby module scope - -warning: unused macro definition: `debug_trace` - --> src/interpreter/core.rs:34:14 - | -34 | macro_rules! debug_trace { - | ^^^^^^^^^^^ - | - = note: `#[warn(unused_macros)]` on by default - -warning: unused imports: `BasicBlockIdGenerator`, `BasicBlock`, `CompareOp`, `EffectMask`, `MirFunction`, and `ValueIdGenerator` - --> src/mir/loop_builder.rs:9:21 - | -9 | MirInstruction, BasicBlock, BasicBlockId, MirFunction, ValueId, - | ^^^^^^^^^^ ^^^^^^^^^^^ -10 | ConstValue, CompareOp, BasicBlockIdGenerator, ValueIdGenerator, EffectMask - | ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ ^^^^^^^^^^ - | - = note: `#[warn(unused_imports)]` on by default - -warning: unused import: `HashSet` - --> src/mir/loop_builder.rs:13:33 - | -13 | use std::collections::{HashMap, HashSet}; - | ^^^^^^^ - -warning: unexpected `cfg` condition value: `llvm` - --> src/backend/mod.rs:13:7 - | -13 | #[cfg(feature = "llvm")] - | ^^^^^^^^^^^^^^^^ - | - = note: expected values for `feature` are: `all-examples`, `cli`, `default`, `dynamic-file`, `gui`, `gui-examples`, `plugins`, and `wasm-backend` - = help: consider adding `llvm` as a feature in `Cargo.toml` - = note: see for more information about checking conditional configuration - = note: `#[warn(unexpected_cfgs)]` on by default - -warning: unexpected `cfg` condition value: `llvm` - --> src/backend/mod.rs:23:7 - | -23 | #[cfg(feature = "llvm")] - | ^^^^^^^^^^^^^^^^ - | - = note: expected values for `feature` are: `all-examples`, `cli`, `default`, `dynamic-file`, `gui`, `gui-examples`, `plugins`, and `wasm-backend` - = help: consider adding `llvm` as a feature in `Cargo.toml` - = note: see for more information about checking conditional configuration - -warning: unused import: `MirInstruction` - --> src/backend/vm_phi.rs:9:41 - | -9 | use crate::mir::{BasicBlockId, ValueId, MirInstruction}; - | ^^^^^^^^^^^^^^ - -warning: unused import: `super::Usize` - --> src/bid/types.rs:1:5 - | -1 | use super::Usize; - | ^^^^^^^^^^^^ - -warning: unused import: `std::os::raw::c_char` - --> src/bid/plugin_api.rs:2:5 - | -2 | use std::os::raw::c_char; - | ^^^^^^^^^^^^^^^^^^^^ - -warning: unused imports: `NyashHostVtable`, `NyashMethodInfo`, and `NyashPluginInfo` - --> src/bid/plugins/filebox/mod.rs:7:18 - | -7 | use crate::bid::{NyashPluginInfo, NyashMethodInfo, NyashHostVtable}; - | ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ - -warning: unused imports: `SeekFrom` and `Seek` - --> src/bid/plugins/filebox/mod.rs:10:28 - | -10 | use std::io::{Read, Write, Seek, SeekFrom}; - | ^^^^ ^^^^^^^^ - -warning: unused imports: `c_char` and `c_void` - --> src/bid/plugins/filebox/mod.rs:11:20 - | -11 | use std::os::raw::{c_char, c_void}; - | ^^^^^^ ^^^^^^ - -warning: unused imports: `CStr` and `CString` - --> src/bid/plugins/filebox/mod.rs:13:16 - | -13 | use std::ffi::{CStr, CString}; - | ^^^^ ^^^^^^^ - -warning: unused import: `std::ffi::c_void` - --> src/bid/loader.rs:4:5 - | -4 | use std::ffi::c_void; - | ^^^^^^^^^^^^^^^^ - -warning: unused imports: `TlvDecoder` and `TlvEncoder` - --> src/bid/generic_plugin_box.rs:5:23 - | -5 | use crate::bid::tlv::{TlvEncoder, TlvDecoder}; - | ^^^^^^^^^^ ^^^^^^^^^^ - -warning: unused import: `crate::bid::types::BidTag` - --> src/bid/generic_plugin_box.rs:6:5 - | -6 | use crate::bid::types::BidTag; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused import: `BoxBase` - --> src/runtime/plugin_loader_v2.rs:10:47 - | -10 | use crate::box_trait::{NyashBox, BoxCore, BoxBase, StringBox}; - | ^^^^^^^ - -warning: unused import: `std::ffi::c_void` - --> src/runtime/plugin_loader_v2.rs:14:9 - | -14 | use std::ffi::c_void; - | ^^^^^^^^^^^^^^^^ - -error[E0599]: no method named `invoke_instance_method` found for struct `RwLockReadGuard<'_, enabled::PluginLoaderV2>` in the current scope - --> src/backend/vm.rs:548:34 - | -548 | match loader.invoke_instance_method(&plugin.box_type, method, plugin.instance_id, &arg_values) { - | ^^^^^^^^^^^^^^^^^^^^^^ method not found in `RwLockReadGuard<'_, PluginLoaderV2>` - -warning: unused variable: `registry` - --> src/box_factory/plugin.rs:53:13 - | -53 | let registry = get_global_registry(); - | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_registry` - | - = note: `#[warn(unused_variables)]` on by default - -warning: variable does not need to be mutable - --> src/interpreter/expressions/calls.rs:734:13 - | -734 | let mut is_builtin = is_builtin_box(parent); - | ----^^^^^^^^^^ - | | - | help: remove this `mut` - | - = note: `#[warn(unused_mut)]` on by default - -warning: variable does not need to be mutable - --> src/interpreter/objects.rs:1106:17 - | -1106 | let mut is_builtin = is_builtin_box(parent_name); - | ----^^^^^^^^^^ - | | - | help: remove this `mut` - -warning: unused variable: `args` - --> src/instance_v2.rs:147:28 - | -147 | pub fn init(&mut self, args: &[Box]) -> Result<(), String> { - | ^^^^ help: if this is intentional, prefix it with an underscore: `_args` - -warning: unused variable: `nyash_value` - --> src/instance_v2.rs:289:21 - | -289 | if let Some(nyash_value) = self.fields_ng.lock().unwrap().get(field_name) { - | ^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_nyash_value` - -warning: variable does not need to be mutable - --> src/mir/builder.rs:85:13 - | -85 | let mut function = MirFunction::new(signature, entry); - | ----^^^^^^^^ - | | - | help: remove this `mut` - -warning: unused variable: `block_id` - --> src/mir/loop_builder.rs:246:39 - | -246 | fn mark_block_unsealed(&mut self, block_id: BasicBlockId) -> Result<(), String> { - | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_block_id` - -warning: unused variable: `block_id` - --> src/mir/loop_builder.rs:273:49 - | -273 | fn get_variable_at_block(&self, name: &str, block_id: BasicBlockId) -> Option { - | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_block_id` - -warning: unused variable: `dst` - --> src/backend/vm_phi.rs:48:9 - | -48 | dst: ValueId, - | ^^^ help: if this is intentional, prefix it with an underscore: `_dst` - -warning: unused variable: `f` - --> src/bid/plugin_api.rs:167:36 - | -167 | pub fn with_alloc(mut self, f: F) -> Self - | ^ help: if this is intentional, prefix it with an underscore: `_f` - -warning: variable does not need to be mutable - --> src/bid/plugin_api.rs:167:26 - | -167 | pub fn with_alloc(mut self, f: F) -> Self - | ----^^^^ - | | - | help: remove this `mut` - -warning: unused variable: `f` - --> src/bid/plugin_api.rs:176:35 - | -176 | pub fn with_free(mut self, f: F) -> Self - | ^ help: if this is intentional, prefix it with an underscore: `_f` - -warning: variable does not need to be mutable - --> src/bid/plugin_api.rs:176:25 - | -176 | pub fn with_free(mut self, f: F) -> Self - | ----^^^^ - | | - | help: remove this `mut` - -warning: unused variable: `f` - --> src/bid/plugin_api.rs:183:34 - | -183 | pub fn with_log(mut self, f: F) -> Self - | ^ help: if this is intentional, prefix it with an underscore: `_f` - -warning: variable does not need to be mutable - --> src/bid/plugin_api.rs:183:24 - | -183 | pub fn with_log(mut self, f: F) -> Self - | ----^^^^ - | | - | help: remove this `mut` - -warning: unused variable: `args` - --> src/runtime/plugin_loader_v2.rs:352:46 - | -352 | pub fn create_box(&self, box_type: &str, args: &[Box]) -> BidResult> { - | ^^^^ help: if this is intentional, prefix it with an underscore: `_args` - -For more information about this error, try `rustc --explain E0599`. -warning: `nyash-rust` (lib) generated 33 warnings -error: could not compile `nyash-rust` (lib) due to 2 previous errors; 33 warnings emitted diff --git a/build_wasm_errors.txt b/build_wasm_errors.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/archive/consultations/gemini_builtin_box_plugin_consultation.txt b/docs/archive/consultations/gemini_builtin_box_plugin_consultation.txt new file mode 100644 index 00000000..77ce2933 --- /dev/null +++ b/docs/archive/consultations/gemini_builtin_box_plugin_consultation.txt @@ -0,0 +1,113 @@ +Nyashプログラミング言語の革命的設計変更について深い技術的相談をお願いします。 + +【背景】 +Nyashは「Everything is Box」哲学を掲げるプログラミング言語です。現在、3種類のBoxが存在します: +1. ビルトインBox(StringBox, IntegerBox等)- Rustで静的リンク +2. プラグインBox(FileBox等)- 動的ライブラリ(.so)で提供 +3. ユーザー定義Box(box Person等)- Nyashコードで定義 + +【現状の問題】 +現在、2つの異なるプラグインシステムが並存しています: +- plugin_loader.rs(1217行): ビルトインBoxを動的ライブラリ化するシステム(未使用) +- plugin_loader_v2.rs(906行): 汎用プラグインシステム(BID-FFI) + +合計2000行以上の重複コードが存在し、メンテナンスが困難です。 + +【革命的提案:ビルトインBox完全プラグイン化】 + +すべてのBox(StringBox、IntegerBox含む)をプラグインとして実装する提案です。 + +```rust +// 現在 +ビルトインStringBox → Rust静的リンク +プラグインFileBox → 動的ロード(.so) + +// 提案 +すべてのBox → プラグイン(.so)として統一 +``` + +【実装案】 +```rust +// コアBoxの定義 +const CORE_BOXES: &[&str] = &[ + "libnyash_string_box.so", + "libnyash_integer_box.so", + "libnyash_bool_box.so", + "libnyash_console_box.so", // print用 +]; + +// 起動時自動ロード +fn main() { + for plugin in CORE_BOXES { + plugin_loader.load_required(plugin)?; + } +} +``` + +【期待されるメリット】 +1. コード削減:plugin_loader.rs(1217行)を完全削除 +2. 統一性:「Everything is Box」の究極の実現 +3. 柔軟性:StringBoxすら置き換え可能(カスタムString実装など) +4. ビルド高速化:本体が軽量化 +5. 配布の柔軟性:必要なBoxだけ選択可能 +6. 開発の独立性:各Boxを独立して開発・テスト可能 + +【懸念事項と対策案】 + +1. パフォーマンス +- 懸念:FFI境界でのオーバーヘッド +- 分析:C関数呼び出しなのでナノ秒レベル、実用上問題なし? + +2. デバッグの困難さ +- 懸念:エラー時のスタックトレースが不明瞭 +- 対策案: + a) プラグイン側での詳細ロギング + b) デバッグシンボルの保持 + c) プラグイン単体テストの充実 + +3. 起動時間 +- 懸念:多数のプラグインロードで遅くなる? +- 対策案:コアBoxのみ必須、他は遅延ロード + +4. 配布の複雑さ +- 懸念:実行ファイル+多数の.soファイル +- 対策案:標準パスに配置、設定ファイルで管理 + +【深く検討してほしい点】 + +1. 技術的妥当性 +- この設計は本当に実現可能で健全でしょうか? +- 見落としている致命的な問題はありませんか? + +2. パフォーマンスへの実影響 +- FFIオーバーヘッドは本当に無視できるレベルでしょうか? +- 頻繁に呼ばれるメソッド(toString等)での累積的影響は? + +3. エコシステムへの影響 +- すべてがプラグインになることで、ライブラリ開発はどう変わりますか? +- パッケージマネージャーの設計にどんな影響がありますか? + +4. 他言語での前例 +- 同様のアプローチを採用した言語はありますか? +- 成功例・失敗例から学べることは? + +5. セキュリティ +- コアBoxまでプラグイン化することのセキュリティリスクは? +- 悪意のあるStringBox置き換えなどへの対策は? + +6. 開発体験 +- デバッグの困難さは実際どの程度深刻でしょうか? +- IDE統合やデバッガサポートはどうなりますか? + +7. 段階的移行戦略 +- 一気に移行すべきか、段階的に移行すべきか? +- 既存ユーザーへの影響を最小化する方法は? + +8. 長期的な保守性 +- 5年後、10年後もこの設計は維持可能でしょうか? +- 技術的負債になる可能性は? + +【最終的な問い】 +「Everything is Box」哲学を実装レベルでも完全に実現するこの提案は、革新的な美しさか、それとも行き過ぎた純粋主義でしょうか? + +実装の現実性、パフォーマンス、開発体験、エコシステムなど、多角的な視点から深い分析をお願いします。特に、この決定が言語の将来に与える影響について、時間をかけて考察していただければ幸いです。 \ No newline at end of file diff --git a/docs/archive/consultations/mir_debug_infrastructure_consultation.txt b/docs/archive/consultations/mir_debug_infrastructure_consultation.txt new file mode 100644 index 00000000..c073d1f9 --- /dev/null +++ b/docs/archive/consultations/mir_debug_infrastructure_consultation.txt @@ -0,0 +1,170 @@ +Nyash MIRレベルデバッグインフラストラクチャ設計相談 + +【背景】 +NyashはMIR(中間表現)を経由して複数のバックエンドで実行されます: +- VM(現在実装済み) +- JIT(Phase 9で実装予定) +- AOT(将来実装) +- WASM(実装済み) + +現在、デバッグ・メモリリーク検出・パフォーマンス解析機能をVM層で実装することを検討していますが、 +MIRレベルで実装できれば、すべてのバックエンドで統一的に使える理想的な設計になります。 + +【技術的課題】 +1. MIRは低レベル命令(26命令)で、高レベルのBox情報が失われる + - NewBox(type_id=6, args) → 6が何のBoxか分からない + - BoxCall(reg=0, "toString") → どのBox型のメソッドか不明 + +2. MIRは実行前の静的表現なので、実行時情報の追跡が困難 + - Boxの生成・破棄タイミング + - メソッド実行時間の計測 + - メモリ使用量の追跡 + +3. 各バックエンドでの実装の違い + - VM: スタックベース、インタープリター + - JIT: ネイティブコード生成 + - WASM: 別の仮想マシン + +【設計案1: MIRデバッグ命令の追加】 +```rust +pub enum MIRInstruction { + // 既存の命令 + NewBox(u16, Vec), + BoxCall(RegisterIndex, RegisterIndex, String, Vec), + + // デバッグ専用命令(本番では無視) + DebugBoxCreate(RegisterIndex, String), // Box型名を記録 + DebugMethodEnter(String, Vec), // メソッド開始 + DebugMethodExit(RegisterIndex), // メソッド終了 + DebugSnapshot(String), // 任意の時点のスナップショット +} +``` + +メリット: +- MIRレベルで完結 +- すべてのバックエンドで同じデバッグ情報 + +デメリット: +- MIRが肥大化 +- 本番実行時のオーバーヘッド + +【設計案2: MIRメタデータの分離】 +```rust +pub struct MIRModule { + pub functions: HashMap, + pub constants: Vec, + pub debug_info: Option, // デバッグ時のみ生成 +} + +pub struct MIRDebugInfo { + // 命令インデックス → デバッグ情報 + instruction_map: HashMap, + + // type_id → Box型名 + type_names: HashMap, + + // ソースマップ + source_map: SourceMap, +} +``` + +メリット: +- MIR本体はクリーン +- デバッグ時のみメタデータ生成 + +デメリット: +- 実行時追跡には各バックエンドでのフック必要 + +【設計案3: MIRプロファイリング拡張】 +```rust +pub trait MIRExecutor { + // 基本実行 + fn execute(&mut self, module: &MIRModule) -> Result<(), Error>; + + // プロファイリング付き実行 + fn execute_with_profiling( + &mut self, + module: &MIRModule, + profiler: &mut dyn MIRProfiler + ) -> Result<(), Error>; +} + +pub trait MIRProfiler { + fn on_instruction(&mut self, pc: usize, inst: &MIRInstruction); + fn on_box_create(&mut self, type_id: u16, reg: RegisterIndex); + fn on_method_call(&mut self, receiver: RegisterIndex, method: &str); + // ... +} +``` + +メリット: +- 各バックエンドが同じプロファイラーインターフェースを実装 +- 柔軟な拡張が可能 + +デメリット: +- 各バックエンドでの実装が必要 + +【設計案4: MIR静的解析による事前情報抽出】 +```rust +pub struct MIRAnalyzer { + pub fn analyze(module: &MIRModule) -> AnalysisResult { + // Box生成パターンの検出 + let box_creations = find_box_creations(&module); + + // メソッド呼び出しグラフの構築 + let call_graph = build_call_graph(&module); + + // 潜在的なメモリリークパターン + let leak_patterns = detect_leak_patterns(&module); + + AnalysisResult { + box_creations, + call_graph, + leak_patterns, + // ... + } + } +} +``` + +メリット: +- 実行前に多くの情報を取得 +- オーバーヘッドなし + +デメリット: +- 動的な振る舞いは追跡できない + +【質問事項】 + +1. MIRレベルでのデバッグ実装について、どの設計案が最も実用的でしょうか? + +2. 他の言語(LLVM IR、Java bytecode、.NET IL等)では、 + このような問題をどのように解決していますか? + +3. MIR命令セットの拡張 vs メタデータ分離、 + どちらがパフォーマンスと保守性のバランスが良いでしょうか? + +4. JIT/AOTコンパイル時にデバッグコードを埋め込む方法として、 + 効率的なアプローチはありますか? + +5. WASMのような異なる実行環境でも統一的にデバッグ情報を + 扱う方法についてアドバイスをお願いします。 + +【現在のMIR命令セット(26命令)】 +- 基本: Const, Move, Copy +- 算術: Add, Sub, Mul, Div, Mod, Neg +- 比較: Eq, Ne, Lt, Le, Gt, Ge +- 論理: And, Or, Not +- Box: NewBox, BoxCall, GetField, SetField +- 制御: Br, Jmp, Call, Ret +- メモリ: RefNew, RefGet, RefSet +- 型: AsType, IsType + +【Nyashの設計哲学】 +- Everything is Box - すべてがBoxオブジェクト +- メモリ安全性重視 +- 初学者フレンドリー +- 高速実行(VM実装で13.5倍高速化達成) + +専門的な観点から、MIRレベルでの統一デバッグインフラストラクチャの +実現可能性と最適な設計についてアドバイスをお願いします。 \ No newline at end of file diff --git a/docs/development/current/CURRENT_TASK.md b/docs/development/current/CURRENT_TASK.md index 6604ccc1..d9ce99c7 100644 --- a/docs/development/current/CURRENT_TASK.md +++ b/docs/development/current/CURRENT_TASK.md @@ -1,74 +1,51 @@ -# 🎯 CURRENT TASK - 2025-08-26(Context Reset / Fresh Focus) +# 🎯 CURRENT TASK - 2025-08-26(Phase 9.79b Kickoff) -コンテキストを「0%」にリセットし、いま必要なことだけに集中するにゃ。 +コンテキストを最小化して、次フェーズへの導線だけ残すにゃ。 -## ⏱️ 今日のフォーカス(Phase 9.79a: Unified Dispatch + P2P Polish) -- 判断: 統一Box設計は「非侵襲のディスパッチ統一」から入る → P2PBox磨きを同時並行 -- 目的: ユニバーサルメソッド(toString/type/equals/clone)をVM/Interpreter前段で統一 + P2PBoxのmulti-node/async UX安定化 +## ⏱️ 今日のフォーカス(Phase 9.79b: Unified IDs → VM Thunks) +- 目的: Box種別(builtin/user/plugin)をMIR/VMで数値ID+スロット統一に移行し、Phase 10(JIT)の足場を固める。 -### 直近の実行タスク(小さく早く) -1) ユニバーサルメソッドの前段ディスパッチ(非侵襲) - - VM/Interpreterで`toString/type/equals/clone`を共通ヘルパにマップ(トレイト変更なし) -2) P2PBox磨き(multi-node/async/解除) - - share/cloneセマンティクス:share=共有, clone=新規(実装済みの明文化) - - unregisterの安全化(endpoint一致 or refcount) - - onOnce/off のE2Eテスト追加 - - VM表示整合(getLast*/debug_* の toString/Console) -3) E2Eスモーク更新 - - self→self, two-node ping-pong(安定) - - asyncデモ(TimeBox併用で確実に出力) +### 直近タスク(小さく早く) +1) 9.79b.1: Unified Registry IDs + Builder Slotting + - 型ID/メソッドスロットの導入(レジストリ) + - ユニバーサルメソッド低スロット予約(0..3) + - Builderが解決可能なBoxCallに`method_id`を付与(未解決は遅延) +2) 9.79b.2: VM VTable Thunks + Mono-PIC + - `execute_boxcall`をvtable+thunkの単一路線へ + - call-site単位のモノモーフィックPICを追加 -### すぐ試せるコマンド(最小) +### すぐ試せるコマンド ```bash -# Rust(Release) cargo build --release -j32 -./target/release/nyash --help - -# Plugin デバッグ実行(任意) -NYASH_DEBUG_PLUGIN=1 ./target/release/nyash --backend vm local_tests/extern_console_log.nyash || true - -# WASM(Web配布) -cd projects/nyash-wasm && wasm-pack build --target web --out-dir pkg +./target/release/nyash examples/p2p_self_ping.nyash +./target/release/nyash examples/p2p_ping_pong.nyash ``` -## 現在の地図(Done / Doing / Next) +## 現在の地図(Done / Next) -### ✅ 完了 -- PluginHostファサード導入・移行(create/invoke/extern) -- TLVヘッダ/引数/ハンドルの共通化(`plugin_ffi_common.rs`) -- Interpreter分割の導線: `eval.rs` / `calls.rs` / `methods_dispatch.rs` 抽出 -- ログ静音の基盤: `idebug!`(NYASH_DEBUG=1 で有効)を calls/core/statements に適用 -- MIR modular builder ゲート追加(feature: `mir_modular_builder`)/ 整合パッチ投入 +### ✅ 完了(9.79a) +- ユニバーサル前段ディスパッチ(toString/type/equals/clone)Interpreter/VM +- P2P unregister安全化・onOnce/off E2E・self/two-nodeスモーク +- IntentBoxのpayload糖衣(MapBox/JSONBox直渡し可) +- Docs: P2Pリファレンス/サンプル -### 🚧 進行中(小タスク) -- Interpreterログ統一の残り(`delegation.rs` など) -- PluginHost の `resolve_method` キャッシュ化(I/O削減) +### ⏭️ 次(9.79b) +- 9.79b.1: `phase_9_79b_1_unified_registry_ids_and_builder_slotting.md` +- 9.79b.2: `phase_9_79b_2_vm_vtable_thunks_and_pic.md` -### ⏭️ 次アクション(今日~明日) -- 9.79a-M1: ユニバーサル前段ディスパッチ(VM/Interpreter)/ 回帰確認 -- 9.79a-M2: P2P unregister安全化 + onOnce/off E2E + async安定 -- 9.79a-M3: VM表示整合/ Docs更新(言語ガイド・P2Pリファレンス) +## 統一Box設計メモ(唯一参照) +- `docs/ideas/other/2025-08-25-unified-box-design-deep-analysis.md` + - 数値ID/スロット/Thunk/PIC/DebugInfoの全体像 -## 決定事項(Unified Box設計メモ) -- ドキュメント: `docs/ideas/other/2025-08-25-unified-box-design-deep-analysis.md` -- 判断: まずはディスパッチャ層でユニバーサルメソッドを統一(トレイト変更なし) -- P2Pは共有セマンティクス(share=共有, clone=新規)を維持しつつ unregister 正式化へ - -## 参考リンク(唯一参照/ゲート) -- MIR命令セット(26命令): `docs/reference/mir/INSTRUCTION_SET.md` -- Phase 9.79(P2P): `docs/development/roadmap/phases/phase-9/phase_9_79_p2pbox_rebuild.md` -- Phase 9.79a(Unified Dispatch + P2P Polish): `docs/development/roadmap/phases/phase-9/phase_9_79a_unified_box_dispatch_and_p2p_polish.md` -- Phase 9.78h(前段完了): `docs/development/roadmap/phases/phase-9/phase_9_78h_mir_pipeline_stabilization.md` +## 参考リンク +- MIR命令セット: `docs/reference/mir/INSTRUCTION_SET.md` +- Phase 9.79a(完了): `docs/development/roadmap/phases/phase-9/phase_9_79a_unified_box_dispatch_and_p2p_polish.md` +- Phase 9.79b(計画): + - `docs/development/roadmap/phases/phase-9/phase_9_79b_1_unified_registry_ids_and_builder_slotting.md` + - `docs/development/roadmap/phases/phase-9/phase_9_79b_2_vm_vtable_thunks_and_pic.md` - Phase 10(Cranelift JIT主経路): `docs/development/roadmap/phases/phase-10/phase_10_cranelift_jit_backend.md` -## Doneの定義(P2PBox 最小) -- `LocalLoopback` で ping/pong が安定 -- P2PBox API(start/stop/send/broadcast/reply/on)が固まる -- ResultBox経由でエラーが伝搬(E2E テスト含む) -- ログは既定静音(環境変数でデバッグオン) - ## Parking Lot(後でやる) -- NyashValue enum導入(即値最適化) +- NyashValue即値最適化・演算子特化 - トレイト階層化(Comparable/Arithmetic etc.) -- メタプログラミング・パイプライン演算子 -- `mir_modular_builder` をデフォルト化(パリティ後) +- オブジェクトリテラル糖衣(feature `object_literal`)提案: `docs/ideas/improvements/2025-08-26-object-literal-sugar.md` diff --git a/docs/development/roadmap/native-plan/copilot_issues.txt b/docs/development/roadmap/native-plan/copilot_issues.txt deleted file mode 100644 index 1ee844f6..00000000 --- a/docs/development/roadmap/native-plan/copilot_issues.txt +++ /dev/null @@ -1,494 +0,0 @@ -# 🤖 Copilot様 作業予定・課題整理 (Phase 8.6-10 重点フェーズ) -# Generated: 2025-08-19 (Phase 9.75g-0完了・VM性能改善移行) -# Purpose: Claude×Copilot協調開発のための情報共有 - -================================================================================ -🎯 Nyash実行モード併用戦略 -================================================================================ - -## 🌟 インタープリター+コンパイラ併用の価値 - -### 実行モード使い分け -``` -開発時: インタープリター(デバッグ・即時実行・非同期フル対応) -本番時: インタープリター(Pythonのように実用的) - OR - WASM/AOT(性能要求時) -配布時: AOT native(最高性能) -Web時: WASM(ブラウザ対応) -``` - -### インタープリターの強み -- **即時実行**: コンパイル不要で高速開発 -- **デバッグ容易**: 実行時情報の完全把握 -- **非同期完全対応**: Rust async/awaitで真の並行処理 -- **動的性**: 実行時評価・REPL対応 -- **十分な性能**: 多くのユースケースで実用的(Pythonが証明) - -================================================================================ -🎯 Phase 8.6-10 開発ロードマップ (性能最適化・LLVM実装重点) -================================================================================ - -## 🎊 Phase 9.75g-0: BID-FFI Plugin System - 完全完了! ✅ - -Summary: -- ✅ **動的プラグインシステム完成**: FileBoxプラグインで実証 -- ✅ **BID-FFI基盤確立**: 型安全なFFIインターフェース -- ✅ **plugin-tester完成**: 汎用プラグイン診断ツール -- ✅ **型情報管理システム**: nyash.toml外部化、セグフォルト修正 - -**革命的成果**: NyashがプラグインでBox型を動的拡張可能に! - -```nyash -// これが現実になった! -local file = new FileBox() // プラグイン提供 -local db = new PostgreSQLBox() // 将来: プラグイン提供 -local gpu = new CudaBox() // 将来: プラグイン提供 -``` - -References: -- docs/Phase-9.75g-0-BID-FFI-Developer-Guide.md (包括的開発者ガイド) -- tools/plugin-tester/ (プラグイン診断ツール) - ------------------------------------------------------------- - -## 🚨 Phase 8.6: VM性能改善 - 最優先課題(進行中) - -Summary: -- **緊急問題**: VMがインタープリターより0.9倍遅い(性能回帰!) -- **目標**: 2倍以上高速化でVM実行を実用レベルに引き上げ -- **担当**: Copilot主導(GitHub Issue #112) - -Priority: **Critical** -Expected Duration: 1-2週間 -GitHub Issue: #112 (Phase 8.6 VM性能改善) - -### 技術的課題 -```bash -# 現状のベンチマーク結果 -Interpreter: 110.10ms (ベースライン) -VM: 119.80ms (0.9倍 - 遅い...) -Target: 55.00ms (2倍高速化目標) -``` - -### 推定原因と対策 -- **デバッグ出力過多**: `println!`による性能劣化 -- **HashMap操作重い**: ValueId → VM値の変換コスト -- **命令ディスパッチ非効率**: switch文ベースディスパッチ - -### 🤖 Copilot協力期待 -- VM実行時間詳細測定・プロファイリング -- 命令ディスパッチ最適化(direct threading等) -- Box操作インライン化・メモリレイアウト最適化 - -References: -- docs/予定/native-plan/issues/phase_8_6_vm_performance_improvement.md - ------------------------------------------------------------- - -## 📦 Phase 9.8: BIDレジストリ + 自動コード生成ツール - MIR統合の要 - -Summary: -- **Phase 9.75g-0完了により準備完了**: プラグインがMIR経由で全バックエンド利用可能に -- BIDレジストリと、BID→各ターゲットのスタブ生成(import/extern宣言)を自動化 - -Priority: **High** (Phase 8.6完了直後) -Expected Duration: 2-3週間 - -### 🌟 革命的価値 -```bash -# 🎯 1つのプラグインが4バックエンド全対応! -nyash bid gen --target wasm bid.yaml # WASM用import生成 -nyash bid gen --target vm bid.yaml # VM用関数テーブル生成 -nyash bid gen --target llvm bid.yaml # AOT用declare生成(LLVM実装時) -``` - -### Scope/Tasks -- BIDレジストリ仕様(署名・効果・バージョン・依存関係) -- 生成: WASM(importObject), VM(関数テーブル), LLVM(declare), TS/Python(RTEラッパ) -- CLI: `nyash bid gen --target wasm|vm|llvm|ts|py bid.yaml` - -### Acceptance -- console/canvasのBIDから各ターゲットの骨子が自動生成される -- **FileBoxプラグインがVM・WASM・AOT全てで動作** - ------------------------------------------------------------- - -## 🔒 Phase 9.9: ExternCall 権限/ケイパビリティモデル(Sandbox/Allowlist) - -Summary: -- 外部API呼び出しの安全化。BIDに必要権限を宣言し、ホスト側で許可/拒否。WASMはimport allowlist、VM/LLVMは関数テーブルで制御。 - -Scope/Tasks: -- 権限種別(console, canvas, storage, net, audio...)とポリシー -- 実行時プロンプト/設定ファイル/環境変数での許可 -- 失権時の挙動(明示エラー) - -Acceptance: -- 禁止権限のExternCallが実行時にブロックされ、明確なエラーが返る - ------------------------------------------------------------- - -## 🧱 Phase 9.10: NyIR(公開IR)仕様化 + フォーマット + 検証器 - -Summary: -- 26命令MIRを公開IR(NyIR v1)として基本セマンティクス凍結。バージョニング、バイナリ`.nybc`/テキスト`.nyir`、厳格検証器を用意。 - -Scope/Tasks: -- docs/nyir/spec.md(Core+Ext骨子) -- nyir-parser/nyir-serializer(.nyir/.nybc) -- Verifier: 所有森/weak/効果/Bus整合 -- ツール: `nyashel -S`, `nyir-run` - -Acceptance: -- 代表サンプルがNyIRで保存・検証・実行可能 - -References: -- docs/nyir/spec.md -- docs/予定/native-plan/issues/phase_9_10_nyir_spec.md - ------------------------------------------------------------- - -## 🧪 Phase 9.11: Golden NyIR + Differential 実行テスト(CI) - -Summary: -- NyIRダンプをゴールデンとし、interp/vm/wasm/jitの出力一致をCIで検証。 - -Scope/Tasks: -- golden/*.nyir の整備 -- CIで各バックエンド実行→結果一致チェック - -Acceptance: -- 主要サンプルで全バックエンド一致 - ------------------------------------------------------------- - -## 🏆 Phase 10: Cranelift JIT(主経路) + LLVM AOT(後段研究) - -Summary: -- **主経路**: MIR→VMを維持しつつ、ホットパスをCraneliftでJIT化して2倍以上の高速化を狙う -- **LLVM AOT**: 設計資産は維持しつつ、JIT安定後(Phase 11以降)に検討 -- **目標**: VMのホットパス(BoxCall/Array/Map)で体感高速化、ベンチで優位性を実証 - -Priority: **High**(Phase 8.6完了直後着手) -Expected Duration: **実装6-8週間(段階導入)** - -### 🚧 Start Gate(着手前の必須完了) -- MIRダイエット(26命令)整合完了:Printer/Verifier/Optimizer一致・効果ラベル統一 -- Loop SSA復帰:Phi/Seal/Pred更新のVerifierチェック合格 -- TypeOp網羅:is/as/isType/asTypeの早期lowering+Optimizer診断(未lowering検出) -- 軽量スナップショット:TypeOp/extern_call/loop/await/boxcallでゴールデン緑 -- P2PBox再設計(Phase 9.79)完了・E2Eグリーン -- CLI分離テスト導線(`cargo test -p core`)安定 - -### 🔍 実現可能性チェック項目(Cranelift) -- ✅ **技術的基盤**: MIR26整合(TypeOp/WeakRef/Barrier) -- ✅ **VM統計**: `--vm-stats` でホット関数抽出可能 -- 🔄 **Proof of Concept**: MIR→CLIFの最小Lower(算術/比較/分岐) -- ❓ **実装工数**: BoxCall/Array/MapのJIT最適化の妥当性 - -### 🌟 インタープリター併用戦略 -``` -開発・デバッグ: インタープリター(即時実行・完全な情報) -軽量タスク: インタープリター(Pythonライク) -性能要求時: LLVM AOT(1000倍高速化) -Web配布: WASM(ブラウザ対応) -``` - -### 🏗️ Phase 10.1: Proof of Concept(2週間) - -Steps: -1) **JITマネージャ**: プロファイル収集・しきい値設計 -2) **MIR→CLIF最小Lower**: Const/BinOp/Compare/Branch/Return -3) **呼出しABI**: VMとの引数/戻り値・BoxRef受け渡し - -### 🏗️ Phase 10.2: 基本実装(4週間) - -Implementation Steps: -1) `src/backend/cranelift/` 基盤構築 -2) MIR→CLIF Lowerの拡充(Call/BoxCall/Array系) -3) JIT関数テーブル + VM切替の安定化 -4) ベンチ: VM比2×目標、BoxCallホットパス優位 - -### 🌐 Phase 10.3: 非同期の扱い(最小) -- awaitは当面VM側で処理継続(JIT対象外) -- JIT関数は同期区間を優先(将来拡張) - -### 技術アプローチ -🤖 Copilot協力期待: -- **Cranelift統合**: MIR→CLIF Lower -- **VMハイブリッド**: JITスイッチ・例外/フォールバック -- **ホットパス最適化**: BoxCall/Array/Mapの直結最適化 - -### パフォーマンス目標 -- **同期処理**: VM比 2×以上(段階的に引き上げ) -- **起動時間**: 低オーバーヘッド(JIT初回コストを隠蔽) - -### Acceptance Criteria -- インタープリター/VMとの互換性(結果一致) -- ホットパスでの実測高速化(2×) -- 回帰テスト・スナップショットの整備 - -References: -- docs/予定/native-plan/issues/phase_10_x_llvm_backend_skeleton.md - -### 🌟 戦略的決定: ネームスペース統合はLLVM後に実施 - -**理由**: 4バックエンド(Interpreter/VM/WASM/LLVM)全体の知見蓄積後に、最適化された統合設計を一回で実現するため - -**効果**: 後戻り・再設計なしで完璧な統合ネームスペースを実装可能 - -```rust -// Phase 10完了後: 4バックエンド対応統合ネームスペース -pub struct UniversalNamespaceManager { - interpreter_cache: BuiltinCache, - vm_function_table: VmFunctionTable, - wasm_import_object: WasmImports, - llvm_module_linking: LlvmLinker, // LLVM完成後追加 -} -``` - ------------------------------------------------------------- - -## 🧰 Phase 10.1: LLVM 外部関数マッピング方針(プラットフォーム抽象) - -Summary: -- ExternCallのFQN→ネイティブ関数(printf等)への写像レイヤーと、OS差の抽象。初手はLinux/clang、他OSは後続。 - -Scope/Tasks: -- env.console.log → printfテンプレート、他は段階的拡張 -- プラットフォーム切替(feature)とリンク方針 - -Acceptance: -- 代表ExternCall(console.log)がAOTバイナリで出力可能 - ------------------------------------------------------------- - -## 🧩 Phase 10.2: Host API層(C-ABI `ny_host_*` / WASM `nyir_host`) - -Summary: -- Rust依存を薄い宿主APIへ集約。C-ABI公開(ファイル/メモリ/時間等)、WASMは`nyir_host` importで提供。 - -Scope/Tasks: -- `ny_host_*`関数群(read_file/free/clockなど)をC-ABIで実装 -- Nyash側extern宣言と所有移管`*_from_raw`/`*_into_raw` -- WASM: import `nyir_host` 名前空間で最低限の関数提供 - -Acceptance: -- 代表I/OがHost API経由で動作し、Rust実装置換が容易 - ------------------------------------------------------------- - -## 🧱 Phase 10.3: ランタイム層の切り分け(corelang/rt/sys/std) - -Summary: -- corelang(純Nyash), rt(Box ABI/所有/weak/Safepoint/Bus), sys(プラットフォーム), std(Nyash実装)に整理。 - -Scope/Tasks: -- ドキュメント化+最小コードの配置替えスケルトン - -Acceptance: -- 層構造が明文化され、新規実装がガイドに従って進められる - ------------------------------------------------------------- - -## 🧬 Phase 10.4: Box ABI(fat ptr)とLLVM属性(Effects) - -Summary: -- Boxのfat pointer(data*, typeid, flags)の定義、Weakの世代タグ、SafepointのLLVM降ろし、Effect→LLVM属性(readonly/readnone等)。 - -Scope/Tasks: -- LLVM IR側のstruct宣言・属性付与の雛形 - -Acceptance: -- 代表関数で属性が付与され、最適化に寄与(noalias/argmemonly等は可能な範囲で) - ------------------------------------------------------------- - -## 📚 Phase 10.5: コア標準(String/Array/Map)Nyash実装(Rust依存の段階的削減) - -Summary: -- 現在Rust実装に依存している基本コンテナ(String/Array/Map)を、rt/sys層を活用してNyash実装に置換。 - -Scope/Tasks: -- String: {ptr,len,cap}, new/push_str/substr/len、`ny_host_alloc/realloc/free` -- Array: {ptr,len,cap}, push/get/set/len/reserve、要素fini -- Map: 簡易hash、set/get/remove/len、所有規則順守 - -Acceptance: -- 代表サンプルでString/Array/MapがNyash実装で動作し、Rust実装をリンクせずに通る - -References: -- docs/予定/native-plan/issues/phase_10_5_core_std_nyash_impl.md - -## Phase 11-14: Infrastructure & Polish - -### Phase 11: MIR Optimization Framework -- エスケープ解析基盤 -- 型特殊化・ボックス化解除 -- デッドコード除去 - -### Phase 12: Advanced JIT Features -- Profile-guided optimization -- インライン展開 -- レジスタ割り当て最適化 - -### Phase 13: Production Readiness -- GC統合最適化 -- メモリ使用量最適化 -- 起動時間短縮 - -### Phase 14: Packaging/CI polish - -Summary: -- Windows/Linux の配布パッケージ化と CI 整備。 - -Scope/Tasks: -- GitHub Actions: Windows(MSVC)/WSL+cargo-xwin のマトリクス -- dist/: nyash(.exe) + LICENSE/README 同梱 - -Acceptance Criteria: -- リリースアーティファクトが自動生成される - -================================================================================ -🧠 AI大会議 + 実用優先戦略で得られた技術的知見 (2025-08-14更新) -================================================================================ - -## Gemini先生の助言(修正適用) -✅ エスケープ解析・ボックス化解除が性能の鍵 -✅ wasmtime compileは短期的に実用的 → **Phase 9で最優先実装** -✅ WASM実行は確実に高速(13.5倍実証済み) -🔄 Cranelift → LLVM段階的アプローチ → **実用優先でLLVM直接へ** - -## codex先生の助言(重点化) -✅ MIR前倒し実装推奨(全バックエンドが恩恵) -✅ wasmtime互換性管理が重要 → **AOT実装で最重要** -✅ CPU差異対応 (baseline/v3二段ビルド) -✅ 起動時間・割当削減・配布体験がKPI → **AOT価値の核心** - -## Claude統合分析(実用優先) -✅ 実用価値最大化: WASM+AOTで十分な競争力 -✅ 開発効率: Cranelift JITの恩恵限定的(cargo build変わらず) -✅ Everything is Box最適化が差別化の核心 -✅ 時間効率: 2-3ヶ月節約でLLVM集中投資 - -## 🎯 実用優先戦略の確定理由 -- **ユーザー体験**: WASM既に動作、AOTで配布価値追加 -- **開発効率**: Cranelift JITは重複投資(Rust開発環境改善せず) -- **競合優位**: AOT+LLVM早期実現で差別化 -- **リソース効果**: 限られた開発時間の最大効率化 - -================================================================================ -💡 Copilot様への具体的お願い・相談事項 -================================================================================ - -## 🔧 Phase 8.6 VM性能改善 (最優先) - -### VM実行時間詳細測定・プロファイリング -❓ 命令ディスパッチのボトルネック特定方法は? -❓ HashMap操作の最適化戦略は? -❓ デバッグ出力削除による性能改善測定は? - -### VM最適化実装 -❓ Direct threading実装の現実的アプローチは? -❓ Register-based VM への移行可能性は? -❓ Box操作インライン化の効果的な実装は? - -## 🚀 長期戦略相談 - -### インタープリター併用戦略 -❓ 開発時と本番時の最適な使い分け方法は? -❓ インタープリターとコンパイラの互換性保証は? -❓ Pythonライクな実用性の実現方法は? - -### Phase 10 LLVM実現可能性調査 (研究段階) -❓ MIR→LLVM IR変換の基本的な実装戦略は? -❓ Box型のLLVM表現として最適なアプローチは? -❓ C-ABIとの統合によるプラグイン連携可能性は? -❓ 現実的な開発期間での完成可能性評価は? - -### Everything is Box最適化 -❓ Box操作の根本的高速化戦略は? -❓ エスケープ解析によるスタック化判定は? -❓ 型特殊化・ボックス化解除の実装戦略は? - -### ベンチマーク戦略 -❓ インタープリター/VM/WASM/LLVMの性能比較方法は? -❓ 非同期処理のベンチマーク設計は? -❓ 実用アプリケーションでの測定指標は? - -================================================================================ -📊 進捗管理・コミュニケーション -================================================================================ - -## 🤝 協調開発ルール - -### コミット・マージ戦略 -✅ 大きな変更前にはdocs/CURRENT_TASK.mdで情報共有 -✅ ベンチマーク機能は最優先で維持 -✅ CLI統合は両機能を統合的に対応 -✅ 競合発生時は機能優先度で解決 - -### 進捗報告 -📅 週次: 進捗状況をCURRENT_TASK.mdに反映 -📅 完了時: 新機能のベンチマーク結果を共有 -📅 問題発生: AI大会議で技術的相談 - -### 品質保証 -✅ cargo check でビルドエラーなし -✅ 既存ベンチマークが regression なし -✅ 新機能のドキュメント整備 -✅ テストケース追加・CI通過 - -================================================================================ -🎯 期待される成果・インパクト -================================================================================ - -## Phase 8-9完了時の成果 (達成済み・進行中) -🏆 RefNew/RefGet/RefSet WASM完全動作 -🏆 Box操作ベンチマーク追加 -🏆 メモリレイアウト最適化効果測定 -🏆 26命令MIR階層化完了(Phase 8.5) -🔄 **VM性能改善進行中(Phase 8.6)** - GitHub Issue #112 -🏆 **Phase 9.75g-0 BID-FFI Plugin System完全完了** -🏆 警告削減100%達成(Phase 9.75j) -🏆 BoxCall実装・wasmtime更新(Phase 9.77) - -## Phase 10以降の展望 -🚀 **WASM復旧完了** (Phase 9.77): 基本機能の完全動作 -🚀 **Cranelift JIT** (Phase 10): VM比2×以上の高速化(段階導入) -🚀 **非同期ネイティブ実装** (Phase 10.2): async/await完全対応 -🚀 **インタープリター併用** : 開発・本番両対応 - -## 言語としての完成度向上 -💎 Everything is Box哲学のネイティブ実現 -💎 インタープリター+コンパイラの最適併用 -💎 4つの実行形態対応(Interpreter/VM/WASM/AOT) -💎 Pythonライクな実用性+C++並みの性能 - -================================================================================ -📞 連絡・相談方法 -================================================================================ - -技術的相談や進捗報告は、以下の方法でお気軽にどうぞ: - -1. 📝 GitHub Issues・Pull Request -2. 📋 docs/CURRENT_TASK.md コメント -3. 🤖 AI大会議 (重要な技術決定) -4. 💬 コミットメッセージでの進捗共有 - -どんな小さなことでも相談大歓迎です! -一緒にNyashを最高の言語にしていきましょう🚀 - -================================================================================ -最終更新: 2025-08-19 (Phase 9.75g-0完了・VM性能改善最優先・LLVM調査段階化) -作成者: Claude (BID-FFIプラグインシステム完了 + 最新優先順位反映) - -🎯 重要な変更点: -- ✅ **Phase 9.75g-0 BID-FFI Plugin System完全完了** (動的プラグインシステム実現) -- 🔄 **Phase 8.6 VM性能改善を最優先** (進行中 - GitHub Issue #112) -- 📦 **Phase 9.8 BIDレジストリ** (Phase 8.6完了後の次期重点) -- 🔍 **Phase 10 LLVM** (実現可能性調査・検証段階として位置づけ) -- 🌟 **ネームスペース統合戦略変更** (LLVM完成後に4バックエンド統合設計) -- 📅 **優先順位明確化**: VM性能 → BIDレジストリ → LLVM調査 の順序 -================================================================================ diff --git a/docs/development/roadmap/phases/00_MASTER_ROADMAP.md b/docs/development/roadmap/phases/00_MASTER_ROADMAP.md new file mode 100644 index 00000000..27703cfa --- /dev/null +++ b/docs/development/roadmap/phases/00_MASTER_ROADMAP.md @@ -0,0 +1,219 @@ +# 🚀 Nyash開発マスタープラン + +Status: Active Development +Last Updated: 2025-08-26 +Purpose: Claude×Copilot×ChatGPT協調開発の総合ロードマップ + +## 📍 現在位置 + +- **現在フェーズ**: Phase 8.6 VM性能改善(進行中) +- **次フェーズ**: Phase 9 JIT実装 +- **詳細タスク**: [CURRENT_TASK.md](../../current/CURRENT_TASK.md) + +## 🗺️ フェーズ概要 + +| Phase | 状態 | 概要 | 詳細リンク | +|-------|------|------|------------| +| 8.4 | ✅完了 | AST→MIR Lowering完全実装 | [phase_8_4_ast_mir_lowering.md](phase-8/phase_8_4_ast_mir_lowering.md) | +| 8.5 | ✅完了 | MIRダイエット(35→26命令) | [phase_8_5_mir_35_to_26_reduction.md](phase-8/phase_8_5_mir_35_to_26_reduction.md) | +| 8.6 | 🔄進行中 | VM性能改善(0.9倍→2倍以上) | [phase_8_6_vm_performance_improvement.md](phase-8/phase_8_6_vm_performance_improvement.md) | +| 9 | 📅予定 | JIT実装 | [phase-9/](phase-9/) | +| 9.75g-0 | ✅完了 | BID-FFI Plugin System | [Phase-9.75g-0-BID-FFI-Developer-Guide.md](phase-9/Phase-9.75g-0-BID-FFI-Developer-Guide.md) | +| 9.8 | 📅予定 | BIDレジストリ + 自動コード生成 | [phase_9_8_bid_registry_and_codegen.md](phase-9/phase_9_8_bid_registry_and_codegen.md) | +| 10 | 📅予定 | Cranelift JIT(主経路) | [phase_10_cranelift_jit_backend.md](phase-10/phase_10_cranelift_jit_backend.md) | +| 11+ | 🔮将来 | LLVM AOT(研究段階) | 後段検討 | + +--- + +## 🎯 Nyash実行モード併用戦略 + +### 🌟 インタープリター+コンパイラ併用の価値 + +#### 実行モード使い分け +``` +開発時: インタープリター(デバッグ・即時実行・非同期フル対応) +本番時: インタープリター(Pythonのように実用的) + OR + WASM/AOT(性能要求時) +配布時: AOT native(最高性能) +Web時: WASM(ブラウザ対応) +``` + +#### インタープリターの強み +- **即時実行**: コンパイル不要で高速開発 +- **デバッグ容易**: 実行時情報の完全把握 +- **非同期完全対応**: Rust async/awaitで真の並行処理 +- **動的性**: 実行時評価・REPL対応 +- **十分な性能**: 多くのユースケースで実用的(Pythonが証明) + +--- + +## 📊 Phase別詳細 + +### 🚨 Phase 8.6: VM性能改善 - 最優先課題(進行中) + +**Summary**: +- **緊急問題**: VMがインタープリターより0.9倍遅い(性能回帰!) +- **目標**: 2倍以上高速化でVM実行を実用レベルに引き上げ +- **担当**: Copilot主導(GitHub Issue #112) + +**技術的課題**: +```bash +# 現状のベンチマーク結果 +Interpreter: 110.10ms (ベースライン) +VM: 119.80ms (0.9倍 - 遅い...) +Target: 55.00ms (2倍高速化目標) +``` + +**推定原因と対策**: +- **デバッグ出力過多**: `println!`による性能劣化 +- **HashMap操作重い**: ValueId → VM値の変換コスト +- **命令ディスパッチ非効率**: switch文ベースディスパッチ + +--- + +### 🎊 Phase 9.75g-0: BID-FFI Plugin System - 完全完了! ✅ + +**革命的成果**: NyashがプラグインでBox型を動的拡張可能に! + +```nyash +// これが現実になった! +local file = new FileBox() // プラグイン提供 +local db = new PostgreSQLBox() // 将来: プラグイン提供 +local gpu = new CudaBox() // 将来: プラグイン提供 +``` + +**References**: +- [Phase-9.75g-0-BID-FFI-Developer-Guide.md](phase-9/Phase-9.75g-0-BID-FFI-Developer-Guide.md) +- tools/plugin-tester/ (プラグイン診断ツール) + +--- + +### 📦 Phase 9.8: BIDレジストリ + 自動コード生成ツール + +**Summary**: +- Phase 9.75g-0完了により準備完了 +- BID→各ターゲットのスタブ生成自動化 + +**革命的価値**: +```bash +# 🎯 1つのプラグインが4バックエンド全対応! +nyash bid gen --target wasm bid.yaml # WASM用import生成 +nyash bid gen --target vm bid.yaml # VM用関数テーブル生成 +nyash bid gen --target llvm bid.yaml # AOT用declare生成(LLVM実装時) +``` + +--- + +### 🏆 Phase 10: Cranelift JIT(主経路) + +**Summary**: +- MIR→VMを維持しつつ、ホットパスをCraneliftでJIT化 +- 目標: VM比2倍以上の高速化 +- LLVM AOTは設計資産は維持しつつ、Phase 11以降に検討 + +**Start Gate(着手前の必須完了)**: +- ✅ MIRダイエット(26命令)整合完了 +- ✅ VM統計: `--vm-stats` でホット関数抽出可能 +- 🔄 Proof of Concept: MIR→CLIFの最小Lower +- ❓ BoxCall/Array/MapのJIT最適化 + +**実装ステップ**: +1. **Phase 10.1**: Proof of Concept(2週間) +2. **Phase 10.2**: 基本実装(4週間) +3. **Phase 10.3**: 非同期の扱い(最小) + +--- + +## 🧠 AI大会議から得られた技術的知見 + +### Gemini先生の助言 +- ✅ エスケープ解析・ボックス化解除が性能の鍵 +- ✅ wasmtime compileは短期的に実用的 +- ✅ WASM実行は確実に高速(13.5倍実証済み) +- 🔄 Cranelift → LLVM段階的アプローチ + +### codex先生の助言 +- ✅ MIR前倒し実装推奨(全バックエンドが恩恵) +- ✅ wasmtime互換性管理が重要 +- ✅ CPU差異対応 (baseline/v3二段ビルド) +- ✅ 起動時間・割当削減・配布体験がKPI + +### Claude統合分析 +- ✅ 実用価値最大化: WASM+AOTで十分な競争力 +- ✅ 開発効率: Cranelift JITの恩恵限定的 +- ✅ Everything is Box最適化が差別化の核心 +- ✅ 時間効率: 2-3ヶ月節約でLLVM集中投資 + +--- + +## 💡 協調開発への具体的お願い + +### 🔧 Phase 8.6 VM性能改善(最優先) +- ❓ 命令ディスパッチのボトルネック特定方法は? +- ❓ HashMap操作の最適化戦略は? +- ❓ デバッグ出力削除による性能改善測定は? +- ❓ Direct threading実装の現実的アプローチは? + +### 🚀 長期戦略相談 +- ❓ インタープリターとコンパイラの互換性保証は? +- ❓ MIR→LLVM IR変換の基本的な実装戦略は? +- ❓ Box型のLLVM表現として最適なアプローチは? +- ❓ エスケープ解析によるスタック化判定は? + +--- + +## 📊 進捗管理・コミュニケーション + +### 🤝 協調開発ルール +- ✅ 大きな変更前にはdocs/CURRENT_TASK.mdで情報共有 +- ✅ ベンチマーク機能は最優先で維持 +- ✅ 競合発生時は機能優先度で解決 + +### 品質保証 +- ✅ cargo check でビルドエラーなし +- ✅ 既存ベンチマークが regression なし +- ✅ 新機能のドキュメント整備 +- ✅ テストケース追加・CI通過 + +--- + +## 🎯 期待される成果 + +### 達成済み +- 🏆 RefNew/RefGet/RefSet WASM完全動作 +- 🏆 26命令MIR階層化完了(Phase 8.5) +- 🏆 Phase 9.75g-0 BID-FFI Plugin System完全完了 +- 🏆 警告削減100%達成(Phase 9.75j) + +### 進行中・予定 +- 🔄 VM性能改善進行中(Phase 8.6)- GitHub Issue #112 +- 📅 Cranelift JIT(Phase 10): VM比2×以上の高速化 +- 📅 非同期ネイティブ実装: async/await完全対応 +- 📅 インタープリター併用: 開発・本番両対応 + +--- + +## 📞 連絡・相談方法 + +技術的相談や進捗報告は、以下の方法でお気軽にどうぞ: + +1. 📝 GitHub Issues・Pull Request +2. 📋 docs/CURRENT_TASK.md コメント +3. 🤖 AI大会議 (重要な技術決定) +4. 💬 コミットメッセージでの進捗共有 + +どんな小さなことでも相談大歓迎です! +一緒にNyashを最高の言語にしていきましょう🚀 + +--- + +**最終更新**: 2025-08-26 (copilot_issues.txt統合・Markdown化) +**作成者**: Claude (ファイル統合・構造整理) + +### 🎯 重要な変更点 +- ✅ **Phase 9.75g-0 BID-FFI Plugin System完全完了** +- 🔄 **Phase 8.6 VM性能改善を最優先** (進行中) +- 📦 **Phase 9.8 BIDレジストリ** (Phase 8.6完了後の次期重点) +- 🔍 **Phase 10 Cranelift JIT** (主経路として確定) +- 🌟 **統一ロードマップ化** (phasesフォルダに集約) \ No newline at end of file diff --git a/docs/development/roadmap/phases/phase-9/phase_9_79a_unified_box_dispatch_and_p2p_polish.md b/docs/development/roadmap/phases/phase-9/phase_9_79a_unified_box_dispatch_and_p2p_polish.md index 1794d6d9..13d54fa3 100644 --- a/docs/development/roadmap/phases/phase-9/phase_9_79a_unified_box_dispatch_and_p2p_polish.md +++ b/docs/development/roadmap/phases/phase-9/phase_9_79a_unified_box_dispatch_and_p2p_polish.md @@ -1,6 +1,6 @@ # Phase 9.79a: Unified Box Dispatch (Minimal) + P2PBox Polish -Status: Planned +Status: Completed Last Updated: 2025-08-26 Owner: core-runtime @@ -37,6 +37,7 @@ Owner: core-runtime - VM: universal methods 前置ディスパッチ - Interpreter: 同様の前置ディスパッチ - スモーク:既存演算子/print動作の回帰なし + - 進捗: 2025-08-26 達成(VM/Interpreterともに toString/type/equals/clone を前段で統一。cargo build 成功) - M2(Day 3–4) - P2PBox unregister安全化(endpoint一致 or refcount) - E2E: onOnce/off 追加、two-node ping-pong 安定、asyncデモが確実に出力 @@ -44,6 +45,26 @@ Owner: core-runtime - VM表示整合:P2PヘルパのtoString/ConsoleをInterpreterと一致 - Docs更新:言語ガイド/P2Pリファレンス反映 +## Completion Notes (2025-08-26) +- Universal dispatch (toString/type/equals/clone): Interpreter/VMに前段実装・整合確認済み。 +- P2PBox Polish: + - InProcess unregister: endpoint一致時のみunregisterで安全化。 + - E2E: onOnce/off ユニットテスト追加、two-node ping→pong スモーク、self→selfスモーク追加。 + - 受信トレース: getLastFrom/getLastIntentName を受信時に更新。 + - 実用ミニ糖衣: IntentBoxの第2引数に MapBox/JSONBox を直接渡せるよう拡張。 +- Docs: 新規リファレンス追加(P2P)/ 例追加 + - docs/reference/boxes-system/p2p_box.md + - examples/p2p_self_ping.nyash + - examples/p2p_ping_pong.nyash + +Notes: +- 非WASM環境のTimerBoxはダミーのため、async出力の確実化はWASM側のガイドで扱う。ネイティブでは同期スモーク(self→self/二者)で安定確認。 + +## Next (roll-forward) +- Language sugar: Object literal → MapBox lowering(feature flag `object_literal`で段階導入) + - Proposal: docs/ideas/improvements/2025-08-26-object-literal-sugar.md +- WASMガイドにTimer併用のasyncサンプル追記。 + ## リスクと対策 - VM分岐に触るリスク → 型別分岐の“前段”に追加、既存分岐はフォールバックとして維持 - unregister回りの退行 → 一致解除テスト/順次Dropテスト(clone/share/Drop順の組み合わせ)を追加 diff --git a/docs/development/roadmap/phases/phase-9/phase_9_79b_1_unified_registry_ids_and_builder_slotting.md b/docs/development/roadmap/phases/phase-9/phase_9_79b_1_unified_registry_ids_and_builder_slotting.md new file mode 100644 index 00000000..470aed9e --- /dev/null +++ b/docs/development/roadmap/phases/phase-9/phase_9_79b_1_unified_registry_ids_and_builder_slotting.md @@ -0,0 +1,49 @@ +# Phase 9.79b.1: Unified Registry IDs + Builder Slotting + +Status: Planned +Owner: core-runtime +Target: Before Phase 10 (Cranelift JIT) +Last Updated: 2025-08-26 + +## Goals +- Introduce `BoxTypeId`/`MethodId` and stable method slot reservation in the unified registry. +- Resolve method names to slot IDs at MIR builder time when possible. +- Keep MIR instruction set stable (26) while enabling ID-based BoxCall. + +## Scope +- Registry + - Add numeric `BoxTypeId` mapping (type-name → id) and `(type_id, method)` → `slot` table. + - Reserve low slots for universal methods: `0=toString`, `1=type`, `2=equals`, `3=clone`. + - Provide `reserve_method_slot()`, `resolve_slot()` APIs. +- MIR Builder + - When receiver type can be inferred, emit `BoxCall { method_id }` (slot ID) instead of name. + - Add late-bind fallback path for unresolved sites (keeps current behavior). +- Debug scaffolding + - Add `MIRDebugInfo` container types (empty by default) for ID→name mapping (off by default). +- Docs + - Update MIR design note to mention ID-based BoxCall with late-bind fallback. + +## Deliverables +- New IDs and slot APIs in registry +- Builder emits `method_id` when resolvable +- Unit tests for slot reservation and universal slot invariants + +## Non-Goals +- VM vtable/thunk dispatch (handled in 9.79b.2) +- PIC/JIT codegen + +## Risks & Mitigations +- Slot consistency with inheritance: document rule “override keeps parent slot”; add test. +- Partial resolvability: ensure late-bind remains correct and does not regress semantics. + +## Timeline +- 1–2 days + +## Acceptance Criteria +- Tests pass; builder prints BoxCall with numeric `method_id` for resolvable sites. +- Universal methods occupy reserved slots across all types. +- No change to MIR opcode count (26) and existing dumps remain valid except for `method_id` where applicable. + +## Roll-forward +- Proceed to 9.79b.2 (VM vtable/thunk + mono-PIC). + diff --git a/docs/development/roadmap/phases/phase-9/phase_9_79b_2_vm_vtable_thunks_and_pic.md b/docs/development/roadmap/phases/phase-9/phase_9_79b_2_vm_vtable_thunks_and_pic.md new file mode 100644 index 00000000..10ed4296 --- /dev/null +++ b/docs/development/roadmap/phases/phase-9/phase_9_79b_2_vm_vtable_thunks_and_pic.md @@ -0,0 +1,51 @@ +# Phase 9.79b.2: VM VTable Thunks + Mono-PIC + +Status: Planned +Owner: core-runtime +Target: Before Phase 10 (Cranelift JIT) +Last Updated: 2025-08-26 + +## Goals +- Implement unified VM BoxCall path via vtable thunks indexed by `MethodId`. +- Add monomorphic inline cache (PIC) at call sites; prepare for polymorphic expansion. +- Keep behavior identical; improve structure and enable JIT lowering. + +## Scope +- VM Dispatch + - Add `TypeMeta` with `vtable_base`, `version`. + - `execute_boxcall(receiver, method_id, args)`: lookup thunk = `vtable[slot]` and call target. +- PIC (Monomorphic) + - Per call-site cache: `(type_id, version) → target` fast path with fallback. + - Counters for hit/miss (debug only) to validate performance wins. +- Plugin safety (stub) + - Provide thunk replacement and type `version++` API (actual unload handled later with plugin mgr). +- Tests + - BoxCall correctness across builtin/user/plugin (plugin mocked if needed). + - PIC hit on repeated calls; miss on version change. +- Docs + - Update VM README with unified path and PIC diagram. + +## Deliverables +- Unified VM BoxCall path (vtable + thunk) +- Monomorphic PIC +- Test coverage for core scenarios + +## Non-Goals +- Polymorphic PIC (plan only) +- JIT emission (Phase 10) + +## Risks & Mitigations +- Thunk ABI uniformity: define single target signature usable by builtin/VM/plugin shims. +- Cache invalidation: bump `version` on thunk replacement; verify miss logic. + +## Timeline +- 2–3 days + +## Acceptance Criteria +- All existing tests pass; new VM dispatch tests pass. +- Measurable hit rate on hot call-sites in debug stats. +- No observable behavior change from user code perspective. + +## Roll-forward +- Phase 10: Cranelift JIT lowers BoxCall to the same thunks; add poly-PIC and codegen stubs. + diff --git a/docs/ideas/improvements/2025-08-26-object-literal-sugar.md b/docs/ideas/improvements/2025-08-26-object-literal-sugar.md new file mode 100644 index 00000000..f4ac812e --- /dev/null +++ b/docs/ideas/improvements/2025-08-26-object-literal-sugar.md @@ -0,0 +1,80 @@ +# Object Literal Sugar for Nyash (Draft) + +Status: Proposal (target: Phase 9.79b or 9.80) +Author: core-runtime +Last Updated: 2025-08-26 + +## Goals +- Provide ergonomic inline construction of structured data for messaging and config. +- Keep parser stable and avoid ambiguity with blocks and control structures. +- Lower to existing Box types (MapBox/JSONBox) without breaking NyashBox trait. + +## Syntax Candidates +- A) JSON-like literals + - Example: `{ a: 1, b: "x", ok: true }` + - Variant: Allow string keys without quotes; values are Nyash expressions. +- B) Explicit constructors with sugar keyword + - Example: `map { a: 1, b: "x" }` → lowers to `new MapBox()` + sets +- C) JSON string auto-parse contextually + - Example: `"{\"a\":1}"` auto-parsed where JSON is expected (too implicit → avoid as default) + +Recommendation: Start with A) JSON-like object literal lowering to MapBox. + +## Grammar Design (A) +- Token additions: `{`, `}`, `:`, `,` are already present. +- Production: + - PrimaryExpr := ObjectLiteral | existing-primary + - ObjectLiteral := `{` ObjMembers? `}` + - ObjMembers := ObjPair (`,` ObjPair)* (`,`)? + - ObjPair := Identifier `:` Expr +- Key constraints: Identifier (no quotes) initially; string-literal keys as follow-up. +- Values: Any expression; evaluation order left-to-right. + +## Lowering Strategy +- `{ k1: v1, k2: v2 }` → + - `tmp = new MapBox(); tmp.set("k1", (v1)); tmp.set("k2", (v2)); tmp` +- In AST builder: desugar ObjectLiteral into a sequence and final tmp reference. +- Side-effects: preserve evaluation order; each `vi` evaluated once. + +## Ambiguity & Conflict Checks +- With blocks: Nyash does not use `{}` for statement blocks (loop uses `loop(cond) { }` but parser differentiates by context). Ensure lookahead disambiguates after `=` or in expression position. +- With `from`: no conflict. +- With `while/if` (obsolete): not applicable. + +## Types & Interop +- MapBox chosen for mutability and existing rich API. +- Allow JSONBox interop later via `json{ ... }` form or helper. +- IntentBox constructor already accepts MapBox/JSONBox (implemented 2025-08-26). + +## Examples +- `msg = new IntentBox("chat", { text: "hi", user: me.name })` +- `cfg = { retries: 3, verbose: true }` +- `headers = { Accept: "application/json", Host: host }` + +## Validation & Tests +- Parser tests: empty `{}`, single/multi pairs, trailing comma, nested values, errors. +- Runtime tests: MapBox size/keys/values; evaluation order with side effects. +- Negative tests: `{ :1 }`, `{a 1}`, `{a:}`, `{a: 1, , b:2}`. + +## Phased Rollout +- Phase 1 (behind feature flag `object_literal`): parser + lowering to MapBox; docs + examples. +- Phase 2: string-literal keys; nested object/array literals sugar (`[ ... ]`?) once array-literal is designed. +- Phase 3: JSONBox literal form `json{ ... }` (optional). + +## Migration & Back-compat +- No breaking changes; literals are additive syntax. +- Existing code using JSON strings/MapBox continues to work. + +## Open Questions +- Should we permit numeric/bool literals as keys? → No (keys stringify already). +- Trailing comma allowed? → Yes (developer-friendly). +- Pretty-printer/formatter impact? → Add simple rule to keep one-line small maps. + +## Out of Scope (for this proposal) +- Array literal `[ ... ]` (future parallel RFC) +- Spread syntax, computed keys, deep merge helpers + +## Appendix +- Related work: JS object literals, Rust maplit!, Lua tables, TOML inline tables. +- Risks: Parser precedence bugs → mitigate with unit tests + feature flag. + diff --git a/docs/ideas/other/2025-08-25-unified-box-design-deep-analysis.md b/docs/ideas/other/2025-08-25-unified-box-design-deep-analysis.md index 59838d8e..51bcde0b 100644 --- a/docs/ideas/other/2025-08-25-unified-box-design-deep-analysis.md +++ b/docs/ideas/other/2025-08-25-unified-box-design-deep-analysis.md @@ -1,539 +1,427 @@ -# Nyash統一Box設計の深い分析と今後の方向性 -Status: Research +# Nyash統一Box設計の深い分析と実装戦略 +Status: Active Design Created: 2025-08-25 -Priority: High +Updated: 2025-08-26 (Codex深掘り版) +Priority: Critical Related: Everything is Box哲学の実装レベルでの完全実現 -## 現状の統一Box設計 +## 📌 最新の合意事項(2025-08-26) -### 3種類のBoxの存在 -1. **ビルトインBox** - Rustで実装(StringBox, IntegerBox, ConsoleBox等) -2. **プラグインBox** - 動的ライブラリで提供(FileBox等の置き換え可能) -3. **ユーザー定義Box** - Nyashコードで定義(box Person等) +### 2つのAI専門家からの統一見解 +- **Codex (GPT-5)**: ハイブリッドアプローチ推奨、Method ID = Stable Slot Index +- **Claude**: MIRレベル完全統一の重要性を強調 +- **共通結論**: コアBox静的リンク+MIR統一+Thunk indirection = 最適解 -### 現在の統一アーキテクチャ -``` -UnifiedBoxRegistry(統一レジストリ) -├── BuiltinBoxFactory(優先度1) -├── UserDefinedBoxFactory(優先度2) -└── PluginBoxFactory(優先度3) -``` +### 核心的設計決定 +1. **ハイブリッドアプローチ** - コアは静的、拡張はプラグイン +2. **MIRレベル完全統一** - 3種類のBoxを数値IDで区別なく扱う +3. **Stable Slot Index** - メソッドIDは型ごとのvtableスロット番号 +4. **Thunk-based Safety** - プラグインアンロード時の安全性保証 -### 統一の美しさ +## 🎯 統一Box設計の全体像 -1. **透過的な置き換え** - - 同じ名前のBoxをプラグインで上書き可能 - - 実行時の動的切り替えも可能 - -2. **統一インターフェース** - ```rust - pub trait BoxFactory: Send + Sync { - fn create_box(&self, name: &str, args: &[Box]) -> Result, RuntimeError>; - fn box_types(&self) -> Vec<&str>; - fn supports_birth(&self) -> bool; - } - ``` - -3. **優先順位システム** - - ビルトイン > ユーザー定義 > プラグイン - - 予約語保護(StringBox等は上書き不可) - -## InstanceBoxによる完全統一 - -### 統一実装の核心 -```rust -pub struct InstanceBox { - pub class_name: String, // "StringBox", "Person"等 - pub inner_content: Option>, // 内包Box(統一!) - pub fields_ng: Arc>>, - pub methods: Arc>, -} -``` - -### 3つの形態を統一的に扱う -```rust -// ビルトイン -InstanceBox::from_any_box("StringBox", Box::new(StringBox::new("hello"))) - -// プラグイン -InstanceBox::from_any_box("FileBox", plugin_loader.create_box("FileBox")) - -// ユーザー定義 -InstanceBox::from_declaration("Person", vec!["name", "age"], methods) -``` - -## 基本メソッドの統一提案 - -### 問題点 -- `toString()` → `to_string_box()` (Rustの命名規則で異なる) -- `type()` → `type_name()` (微妙に異なる) -- 各Boxで個別実装されていて統一感がない - -### 解決案:NyashBoxトレイトにデフォルト実装 -```rust -pub trait NyashBox: BoxCore + Debug { - // Nyash標準メソッド(デフォルト実装) - fn toString(&self) -> Box { - Box::new(StringBox::new(&self.to_string_box().value)) - } - - fn type(&self) -> Box { - Box::new(StringBox::new(self.type_name())) - } - - fn equals(&self, other: Box) -> Box { - Box::new(BoolBox::new(self.equals_internal(other.as_ref()))) - } - - fn clone(&self) -> Box { - self.clone_box() - } -} -``` - -### VMでの統一的な呼び出し -```rust -pub(super) fn call_box_method(&self, box_value: Box, method: &str, args: Vec>) -> Result, VMError> { - // 基本メソッドは全Boxで使える! - match method { - "toString" => Ok(box_value.toString()), - "type" => Ok(box_value.type()), - "equals" => Ok(box_value.equals(args[0].clone_or_share())), - "clone" => Ok(box_value.clone()), - _ => self.call_specific_method(box_value, method, args) - } -} -``` - -## Gemini先生からの提案(部分) - -### 1. NyashValue Enumの導入 -```rust -pub enum NyashValue { - // 即値(スタック上) - Void, - Bool(bool), - Integer(i64), - Float(f64), - - // ヒープ上の不変値 - String(Arc), - - // 複雑なオブジェクト - Object(Arc), -} -``` - -**メリット**: -- 小さな値のヒープアロケーション回避 -- パターンマッチによる高速ディスパッチ -- 型安全性の向上 - -### 2. トレイトの階層化 -```rust -// 基本トレイト -pub trait NyashBox: Send + Sync + Debug { - fn to_string(&self) -> String; - fn type_name(&self) -> &'static str; - fn equals(&self, other: &dyn NyashBox) -> bool; -} - -// 拡張トレイト -pub trait Comparable: NyashBox { - fn compare(&self, other: &dyn NyashBox) -> Option; -} - -pub trait Arithmetic: NyashBox { - fn add(&self, other: &dyn NyashBox) -> Result, String>; -} -``` - -### 3. メタプログラミング機能 -```rust -pub trait BoxMetadata { - fn on_method_missing(&self, name: &str, args: &[NyashValue]) -> Option; - fn on_field_access(&self, name: &str) -> Option; -} -``` - -## 統一継承の実現 - -### ~~現在の課題~~ → 2025-08-25更新:すべて実装済み! -- ~~ビルトインBoxの継承ができない~~ → ✅ 実装済み! -- ~~プラグインBoxの継承も未実装~~ → ✅ 実装済み! - -### 理想的な統一継承(すでに実現!) -```nyash -// すべて可能になった! -box MyString from StringBox { } // ビルトイン継承 ✅ -box MyFile from FileBox { } // プラグイン継承 ✅ -box Employee from Person { } // ユーザー定義継承 ✅ - -// 多重デリゲーションも可能! -box MultiChild from StringBox, IntegerBox { } // ✅ -``` - -### 実際のコード例(動作確認済み) -```nyash -box EnhancedString from StringBox { - init { prefix, suffix } - - birth(text) { - from StringBox.birth(text) // 透過的にpackに変換される - me.prefix = "【" - me.suffix = "】" - } - - enhanced() { - return me.prefix + me.toString() + me.suffix + "✨" - } -} -``` - -## さらなる美化への道 - -### 1. パイプライン演算子 -```nyash -// 現在 -local result = str.substring(0, 5).toUpperCase().trim() - -// パイプライン版 -local result = str - |> substring(0, 5) - |> toUpperCase() - |> trim() -``` - -### 2. Box階層の整理 -``` -NyashBox (trait) -├── ValueBox (数値・文字列・真偽値) -│ ├── IntegerBox -│ ├── StringBox -│ └── BoolBox -├── ContainerBox (コレクション) -│ ├── ArrayBox -│ └── MapBox -├── IOBox (入出力) -│ ├── ConsoleBox -│ └── FileBox -└── ConcurrentBox (並行処理) - ├── FutureBox - └── ChannelBox -``` - -### 3. エフェクトシステムの美化 -```rust -impl ArrayBox { - #[effect(Pure)] - fn length(&self) -> IntegerBox { } - - #[effect(State)] - fn push(&mut self, item: Box) { } -} -``` - -## 実装優先順位(80/20ルール) - -### 今すぐやるべき(80%) -1. 基本メソッド(toString, type, equals, clone)の統一実装 -2. VMでの統一的なメソッドディスパッチ -3. InstanceBoxのinner_content活用の徹底 - -### 後でじっくり(20%) -1. NyashValue enum導入によるパフォーマンス最適化 -2. トレイト階層化による整理 -3. パイプライン演算子の実装 -4. メタプログラミング機能 -5. 完全な統一継承システム - -## まとめ - -現在のNyashの統一Box設計は、すでに相当美しく実装されている。特に: - -1. **UnifiedBoxRegistry**による透過的な管理 -2. **優先順位システム**による明確な解決 -3. **InstanceBox**による統一的な扱い - -これらは「Everything is Box」哲学を実装レベルで体現している。 - -ユーザー定義Boxをビルトイン/プラグインBoxと完全に同じレベルで扱うことは、強引ではなく、むしろ設計として自然で美しい。この統一により、言語の一貫性と拡張性が大幅に向上する。 - -今後は、基本メソッドの統一実装から始めて、段階的により洗練された設計へと進化させていくのが良いだろう。 - -## 🚀 MIR/VM統一実装計画(2025-08-25追記) - -### 📍 現状の課題 -VMとMIRで、Box型によって異なる処理をしている: +### 1. Box分類の最終決定 ```rust -// VMでの現状:InstanceBoxだけ特別扱い -if let Some(inst) = arc_box.as_any().downcast_ref::() { - // ユーザー定義Box → 関数呼び出しに変換 - let func_name = format!("{}.{}/{}", inst.class_name, method, args.len()); -} else { - // ビルトイン/プラグイン → 直接メソッド呼び出し - self.call_box_method(cloned_box, method, nyash_args)? -} -``` - -### 🎯 統一実装の提案 - -#### 1. 統一メソッドディスパッチインターフェース -```rust -pub trait UnifiedBox: NyashBox { - fn dispatch_method(&self, method: &str, args: Vec>) - -> Result, String> { - // デフォルト実装:既存のメソッド呼び出しを使用 - self.call_method(method, args) - } -} - -// InstanceBoxでのオーバーライド -impl UnifiedBox for InstanceBox { - fn dispatch_method(&self, method: &str, args: Vec>) - -> Result, String> { - // MIR関数へのリダイレクト - let func_name = format!("{}.{}/{}", self.class_name, method, args.len()); - // VM経由で関数呼び出し - } -} -``` - -#### 2. VMの簡素化 -```rust -// 統一後:すべて同じ処理パス -let result = match &recv { - VMValue::BoxRef(arc_box) => { - arc_box.dispatch_method(method, nyash_args)? - } - _ => { - recv.to_nyash_box().dispatch_method(method, nyash_args)? - } -}; -``` - -#### 3. MIRレベルでの統一 -- `BoxCall`命令ですべてのBox型を統一的に処理 -- 型による分岐や特殊処理を削除 -- コンパイル時の最適化は維持 - -### 💎 期待される効果 - -1. **コードの簡素化** - - VM内の条件分岐削除で30%以上のコード削減 - - 新Box型追加時の変更箇所が最小限に - -2. **保守性の向上** - - Box型の実装詳細がVMから隠蔽される - - テストが書きやすくなる - -3. **パフォーマンス** - - 統一的な最適化(メソッドキャッシュ等)が可能 - - 仮想関数テーブルによる高速化の可能性 - -4. **美しさ** - - 「Everything is Box」が実装レベルでも完全に実現 - - シンプルで理解しやすいコード - -### 📅 実装ロードマップ - -1. **Phase 1**: UnifiedBoxトレイトの導入(後方互換性を保ちながら) -2. **Phase 2**: VMでの統一ディスパッチ実装 -3. **Phase 3**: MIRビルダーの簡素化 -4. **Phase 4**: 旧実装の削除とクリーンアップ - -### 🌟 最終的なビジョン - -すべてのBox(ビルトイン、プラグイン、ユーザー定義)が完全に統一された世界: -- 同じインターフェース -- 同じ実行パス -- 同じ最適化機会 - -これこそが「Everything is Box」の究極の実現! - -## 🔌 プラグインローダーv2との統合 - -### 現在のプラグインシステムとの関係 -- プラグインローダーv2がすでに統一的なインターフェースを提供 -- `extern_call`経由での統一的なアクセス -- UnifiedBoxトレイトとの相性は良好 - -### 統合のメリット -- プラグインBoxも`dispatch_method()`で統一処理 -- ホットリロード時も透過的に動作 -- FFI境界を意識しない実装 - -## 📊 パフォーマンス測定計画 - -### 現在のベースライン -- インタープリター基準で13.5倍高速化達成(VM実装) -- BoxCall命令の実行時間が全体の約30% - -### 統一実装後の予測 -- 条件分岐削減で5-10%の高速化期待 -- メソッドキャッシュで追加20%改善の可能性 -- 測定方法:`--benchmark --iterations 1000`で検証 - -## 🔄 移行時の互換性戦略 - -### 段階的移行計画 -1. **Phase 1**: UnifiedBoxトレイトを追加(既存APIは維持) -2. **Phase 2**: 警告付きで旧API使用を通知 -3. **Phase 3**: 内部実装を統一版に切り替え -4. **Phase 4**: 旧APIをdeprecated化 -5. **Phase 5**: 完全削除(6ヶ月後) - -### テスト戦略 -- 既存の全E2Eテストが通ることを保証 -- パフォーマンスリグレッションテスト追加 -- プラグイン互換性テストスイート - -## ⚡ JITコンパイラとの統合(Phase 9準備) - -### 統一メソッドディスパッチの利点 -- JITが最適化しやすい単純な呼び出しパターン -- インライン展開の機会増加 -- 型情報を活用した特殊化 - -### 仮想関数テーブル(vtable)戦略 -```rust -struct BoxVTable { - methods: HashMap>) -> Result, String>>, -} -``` -- 起動時に事前計算 -- JITコンパイル時に直接参照 -- キャッシュフレンドリーな配置 - -## 🔧 具体的な実装タスク(TODO) - -### Phase 1: 基礎実装(1週間) -- [ ] UnifiedBoxトレイトの定義(src/box_trait.rs) -- [ ] StringBox, IntegerBox等への実装 -- [ ] InstanceBoxへのdispatch_method実装 -- [ ] 単体テストの作成 - -### Phase 2: VM統合(2週間) -- [ ] execute_boxcall()の簡素化 -- [ ] InstanceBox特別扱いコードの削除 -- [ ] VMValueとの統合 -- [ ] E2Eテスト全パス確認 -- [ ] ベンチマーク実行と比較 - -### Phase 3: 最適化(1週間) -- [ ] メソッドキャッシュ実装 -- [ ] 頻出メソッドの特殊化 -- [ ] vtable事前計算 -- [ ] JIT統合準備 - -### Phase 4: クリーンアップ(3日) -- [ ] 旧実装コードの削除 -- [ ] ドキュメント更新 -- [ ] CHANGELOG記載 -- [ ] マイグレーションガイド作成 - -### 検証項目 -- [ ] 全Box型でtoString/type/equals/cloneが動作 -- [ ] プラグインBoxの透過的な動作 -- [ ] パフォーマンス改善の確認 -- [ ] メモリ使用量の変化なし - -## 🚀 究極の統一:ビルトインBox完全プラグイン化構想 - -### 現状の二重実装問題 -- **plugin_loader.rs** (1217行) - ビルトインBoxの動的ライブラリ化 -- **plugin_loader_v2.rs** (906行) - プラグインBoxシステム -- 合計2000行以上の重複! - -### 完全プラグイン化の提案 - -#### すべてをプラグインに統一 -```rust -// 現在 -ビルトインFileBox → 静的リンク -プラグインFileBox → 動的ロード(.so) - -// 統一後 -すべてのBox → プラグイン(.so)として実装 -``` - -#### コアBoxの自動ロード戦略 -```rust +// 絶対的コアBox(静的リンク必須)- 10個 const CORE_BOXES: &[&str] = &[ - "libnyash_string_box.so", // StringBox(必須) - "libnyash_integer_box.so", // IntegerBox(必須) - "libnyash_bool_box.so", // BoolBox(必須) - "libnyash_console_box.so", // ConsoleBox(print用) + "NilBox", "BoolBox", "IntegerBox", "FloatBox", + "StringBox", "ArrayBox", "MapBox", + "ConsoleBox", "ResultBox", "MethodBox" ]; -// 起動時に自動ロード -fn init_core_boxes() { - for plugin in CORE_BOXES { - plugin_loader.load_required(plugin) - .expect("Core box loading failed"); +// 準コアBox(静的だが置換可能)- 4個 +const SEMI_CORE_BOXES: &[&str] = &[ + "MathBox", "DebugBox", "TimeBox", "RandomBox" +]; + +// プラグイン推奨Box - 残り全て +const PLUGIN_BOXES: &[&str] = &[ + "FileBox", "NetworkBox", "AudioBox", + "P2PBox", "EguiBox", "WebDisplayBox", // ... +]; +``` + +### 2. 革新的な統一レジストリ設計(Codex提案) + +```rust +pub struct UnifiedBoxRegistry { + // 型名 → 型ID(安定) + type_registry: HashMap, + + // 型メタデータ(vtableベースアドレス含む) + type_meta: Vec, + + // (型ID, メソッド名) → スロット番号(永続的) + slot_index: HashMap<(BoxTypeId, String), SlotIdx>, + + // Thunkプール(固定アドレス、原子的更新可能) + thunks: Vec, + + // グローバルエポック(大規模無効化用) + epoch: AtomicU64, +} + +// 型ごとのメタデータ +struct TypeMeta { + version: AtomicU32, // 動的更新のバージョン + vtable_base: *const *const MethodThunk, // vtableベースポインタ + slot_count: u32, // 割り当て済みスロット数 +} + +// メソッドThunk(間接層) +struct MethodThunk { + target: AtomicPtr, // 実装への原子的ポインタ + sig: Signature, // メソッドシグネチャ + flags: MethodFlags, // 純粋性、インライン可能性等 +} +``` + +## 🚀 MIRレベルでの完全統一実装 + +### 1. 統一MIR命令(最終形) + +```rust +pub enum MirInstruction { + // Box生成(すべて同じ) + BoxNew { + dst: ValueId, + type_id: BoxTypeId, // 数値ID(ビルトイン=1、ユーザー=1000でも同じ) + args: Vec, + }, + + // メソッド呼び出し(すべて同じ) + BoxCall { + dst: Option, + receiver: ValueId, + method_id: MethodId, // 安定したスロット番号 + args: Vec, + effects: EffectFlags, // 純粋性、副作用情報 + }, +} +``` + +### 2. メソッドID解決戦略(Codex推奨) + +```rust +impl MirBuilder { + fn compile_method_call(&mut self, receiver: ValueId, method: &str, args: Vec) { + let receiver_type = self.infer_type(receiver); + + // 静的に解決可能な場合 + if let Some(slot) = self.registry.resolve_slot(receiver_type, method) { + self.emit(MirInstruction::BoxCall { + dst: Some(self.new_value()), + receiver, + method_id: slot, + args, + effects: self.registry.get_method_flags(receiver_type, slot), + }); + } else { + // 動的解決が必要(eval、動的ロード) + self.emit_late_bind_call(receiver, method, args); + } } } ``` -### メリット -1. **コード削減**: plugin_loader.rs (1217行) を完全削除 -2. **統一性**: Everything is Boxの究極の実現 -3. **柔軟性**: StringBoxすら置き換え可能 -4. **ビルド高速化**: 本体が軽量に -5. **配布の柔軟性**: 必要なBoxだけ選択可能 +### 3. VM実装の劇的簡素化 -### 考慮事項 - -#### パフォーマンス -- FFI境界のオーバーヘッドは**ナノ秒レベル** -- 実用上の影響なし - -#### デバッグの課題と対策 ```rust -// 課題:エラー時のスタックトレース -thread 'main' panicked at 'FFI boundary: 0x7f8b2c001234' - -// 対策1:プラグイン側でのロギング -#[no_mangle] -pub extern "C" fn box_method_toString() { - eprintln!("[StringBox::toString] called from {:?}", std::thread::current().id()); +// 現在:Box種類で複雑な分岐 +match determine_box_kind(&receiver) { + BoxKind::Instance => { + // ユーザー定義Boxの特殊処理 + let func_name = format!("{}.{}", class_name, method); + self.call_mir_function(func_name, args)? + }, + BoxKind::Plugin => { + // プラグインのFFI呼び出し + unsafe { plugin_invoke(receiver, method, args) } + }, + BoxKind::Builtin => { + // ビルトインメソッド直接呼び出し + builtin_dispatch(receiver, method, args) + } } -// 対策2:デバッグシンボル保持 -cargo build --features debug-symbols - -// 対策3:プラグイン単体テストの充実 -#[test] -fn test_string_box_methods() { /* ... */ } +// 統一後:完全に均一なディスパッチ! +fn execute_boxcall(&mut self, receiver: ValueId, method_id: MethodId, args: Vec) { + // 1. 受信者の型を取得 + let type_meta = self.get_type_meta(receiver); + + // 2. vtableからThunkを取得 + let thunk = unsafe { *type_meta.vtable_base.add(method_id as usize) }; + + // 3. Thunkのターゲットを原子的に読み取り + let target = thunk.target.load(Ordering::Acquire); + + // 4. 統一的な呼び出し + let result = (target)(receiver, args); + self.push(result); +} ``` -### 実装ロードマップ -1. **Phase A**: コアBoxのプラグイン化 - - StringBox, IntegerBox, BoolBox, ConsoleBox -2. **Phase B**: 起動時自動ロード機構 -3. **Phase C**: plugin_loader.rs削除 -4. **Phase D**: ドキュメント・テスト整備 +## ⚡ 高性能化の核心技術 -### 設定ファイル案 -```toml -# ~/.nyash/config.toml -[plugins] -core_path = "./plugins/core/" -search_paths = ["./plugins", "/usr/lib/nyash/plugins"] +### 1. Polymorphic Inline Cache (PIC) 実装 -[core_boxes] -required = ["string", "integer", "bool", "console"] -optional = ["file", "math", "time"] +```rust +// コールサイトごとのインラインキャッシュ +struct InlineCache { + // モノモーフィックエントリ(最頻出) + mono_type: BoxTypeId, + mono_version: u32, + mono_target: *const fn, + + // ポリモーフィックエントリ(2-4個) + poly_entries: [(BoxTypeId, u32, *const fn); 4], + poly_count: u8, +} + +// JIT生成コード例(疑似コード) +fn generate_pic_stub(cache: &InlineCache) -> Code { + // 1. 受信者の型IDを取得 + // 2. モノモーフィックチェック + if receiver.type_id == cache.mono_type && + receiver.version == cache.mono_version { + jump cache.mono_target // 直接ジャンプ! + } + // 3. ポリモーフィックチェック + for entry in cache.poly_entries[..cache.poly_count] { + if receiver.type_id == entry.0 && receiver.version == entry.1 { + jump entry.2 + } + } + // 4. スローパス + call slow_path_resolver +} ``` -これにより、「Everything is Box」哲学が実装レベルでも完全に実現される! +### 2. メソッドスロットの永続性保証 -## 🔍 統一デバッグインフラストラクチャ(2025-08-26追記) +```rust +impl UnifiedBoxRegistry { + // スロット予約(一度割り当てたら永続) + pub fn reserve_method_slot( + &mut self, + type_id: BoxTypeId, + method: &str, + sig: &Signature + ) -> SlotIdx { + let key = (type_id, method.to_string()); + + // 既存スロットがあれば返す + if let Some(&slot) = self.slot_index.get(&key) { + return slot; + } + + // 新規スロット割り当て(削除後も再利用しない) + let type_meta = &mut self.type_meta[type_id as usize]; + let slot = SlotIdx(type_meta.slot_count); + type_meta.slot_count += 1; + + self.slot_index.insert(key, slot); + slot + } +} +``` + +### 3. 安全なプラグインアンロード + +```rust +impl PluginManager { + fn unload_plugin(&mut self, plugin_id: PluginId) { + // 1. 影響を受ける型とメソッドを列挙 + let affected = self.get_plugin_methods(plugin_id); + + for (type_id, slot) in affected { + // 2. Thunkを原子的にスタブに差し替え + let thunk = &self.registry.get_thunk(type_id, slot); + let stub = get_unloaded_method_stub(); + thunk.target.store(stub, Ordering::Release); + + // 3. 型バージョンをインクリメント(キャッシュ無効化) + let type_meta = &self.registry.type_meta[type_id]; + type_meta.version.fetch_add(1, Ordering::AcqRel); + } + + // 4. RCU/Hazard Pointerで安全に回収 + self.defer_plugin_cleanup(plugin_id); + } +} + +// アンロード後のスタブ関数 +fn unloaded_method_stub(_: ValueId, _: Vec) -> VMValue { + panic!("Method has been unloaded") +} +``` + +## 📊 パフォーマンス分析と予測 + +### 現状のベースライン +- インタープリター比: **13.5倍**高速 +- BoxCall実行時間: 全体の**30%** +- 主なオーバーヘッド: 文字列比較、型判定、間接呼び出し + +### 改善による期待効果 + +| 最適化技術 | 個別改善率 | 全体への影響 | +|-----------|----------|-----------| +| メソッドID化 | 50-70% | 15-21% | +| PICキャッシュ | 80-90% | 24-27% | +| インライン化 | 特定サイト10倍 | 10-25% | +| 純粋性解析 | CSE/LICM可能 | 5-15% | + +### 20倍達成への道筋 +``` +現在: 13.5倍 +目標: 20.0倍(+48%必要) + +達成可能性: +- ID化+PIC: 1.15-1.20倍 +- インライン化: 1.10-1.25倍 +- 効果解析: 1.05-1.15倍 +合計: 1.32-1.73倍 → 17.8-23.4倍(達成可能!) +``` + +## 🛠️ 実装ロードマップ(詳細版) + +### Phase 1: 基盤構築(1週間) +```rust +// Week 1のタスク +- [ ] MethodThunk構造体とアロケーター実装 +- [ ] TypeMetaとvtable管理実装 +- [ ] スロット予約API(reserve_method_slot) +- [ ] 基本的なレジストリ操作 +``` + +### Phase 2: MIR統合(1週間) +```rust +// Week 2のタスク +- [ ] BoxNew/BoxCallの数値ID化 +- [ ] メソッド名→スロット解決 +- [ ] late-bind placeholderサポート +- [ ] デバッグ情報サイドテーブル +``` + +### Phase 3: VM最適化(2週間) +```rust +// Week 3-4のタスク +- [ ] 統一execute_boxcall実装 +- [ ] モノモーフィックPIC実装 +- [ ] ポリモーフィックPIC拡張 +- [ ] ベンチマーク検証 +``` + +### Phase 4: プラグイン対応(1週間) +```rust +// Week 5のタスク +- [ ] プラグインAPIのスロット対応 +- [ ] 安全なアンロード実装 +- [ ] バージョン管理とキャッシュ無効化 +- [ ] 実プラグイン移行(FileBox) +``` + +### Phase 5: JIT準備(継続的) +```rust +// 継続タスク +- [ ] 純粋性フラグの伝搬 +- [ ] インライン可能IRの提供 +- [ ] Craneliftメタデータ整備 +- [ ] PIC codegenサポート +``` + +## 🔍 技術的詳細と実装のコツ + +### デバッグ情報の管理 +```rust +// MIRは数値のみ保持 +struct MirDebugInfo { + // (type_id, slot) → 人間可読情報 + method_names: HashMap<(BoxTypeId, SlotIdx), MethodDebug>, + // PC → ソース位置 + source_map: HashMap, +} + +struct MethodDebug { + type_name: String, + method_name: String, + signature: String, + source_file: PathBuf, + line: u32, +} +``` + +### スレッドセーフティ +```rust +// Read-Copy-Update パターン +impl UnifiedBoxRegistry { + fn update_method(&self, type_id: BoxTypeId, slot: SlotIdx, new_impl: *const fn) { + // 1. 新バージョンを準備 + let new_thunk = MethodThunk { + target: AtomicPtr::new(new_impl), + // ... + }; + + // 2. RCUで安全に更新 + rcu::synchronize(|| { + self.thunks[slot].target.store(new_impl, Ordering::Release); + }); + } +} +``` + +### メモリレイアウト最適化 +```rust +// キャッシュフレンドリーな配置 +#[repr(C, align(64))] // キャッシュライン境界 +struct TypeVTable { + thunks: [MethodThunk; MAX_METHODS_PER_TYPE], +} + +// ホットデータをまとめる +struct HotMethodData { + frequently_called: [MethodThunk; 8], // toString, equals等 + cold_methods: *const ColdMethodTable, +} +``` + +## 💡 結論と次のステップ + +### 統一設計の価値 +1. **簡潔性**: VM/JIT実装が劇的にシンプルに +2. **性能**: 20倍高速化が現実的に達成可能 +3. **安全性**: Thunk indirectionで動的更新も安全 +4. **拡張性**: 新Box型追加が容易 + +### ChatGPT5への相談ポイント +1. **Thunk実装の具体的なアセンブリ** +2. **RCU/Hazard Pointerの実装詳細** +3. **PICのCranelift codegenパターン** +4. **型推論とスロット解決の統合** +5. **デバッガ統合のベストプラクティス** + +### 実装の第一歩 +```rust +// まずはこれを実装! +pub struct MethodThunk { + target: AtomicPtr *const u8>, + #[cfg(debug_assertions)] + debug_name: &'static str, +} + +// そしてスロット予約 +registry.reserve_method_slot(STRING_BOX_ID, "toString", &sig); +``` + +「Everything is Box」の理想が、ついに実装レベルで完全に実現される時が来ました! + +## 🔍 統一デバッグインフラストラクチャ ### 📍 MIRレベルでの統一デバッグ実現 -今までの議論で、MIRレベルでのデバッグ実装が最も理想的であることが判明しました。 +MIRレベルでのデバッグ実装が最も理想的であることが判明しました。 Gemini先生とCodex先生の両方が同じ結論に達しました:**設計案2+3のハイブリッド**が最適解です。 #### 核心設計:メタデータ分離+プロファイリングAPI @@ -737,7 +625,7 @@ impl DeepInspectorBox { } ``` -### 🚀 実装ロードマップ(2025年後半) +### 🚀 統一デバッグ実装ロードマップ #### Phase 1: MIRデバッグ基盤(2週間) - [ ] MIRDebugInfo構造の実装 @@ -764,7 +652,7 @@ impl DeepInspectorBox { - [ ] サンプリングモード - [ ] 増分参照グラフ更新 -### 💎 統一の美しさ +### 💎 統一デバッグの美しさ この設計により、以下が実現されます: diff --git a/docs/reference/boxes-system/p2p_box.md b/docs/reference/boxes-system/p2p_box.md new file mode 100644 index 00000000..331641e1 --- /dev/null +++ b/docs/reference/boxes-system/p2p_box.md @@ -0,0 +1,39 @@ +# P2PBox - Modern P2P Node (InProcess) + +Status: Experimental (Phase 9.79a) + +## Overview +- Structured messaging with `IntentBox(name, payload)` +- Local in-process routing via `MessageBus` +- Deterministic smoke demo available without timers + +## API +- `new P2PBox(nodeId: String, transport: String)` +- `send(to: String|Box, intent: IntentBox) -> ResultBox` +- `on(name: String, handler: MethodRef) -> ResultBox` +- `onOnce(name: String, handler: MethodRef) -> ResultBox` +- `off(name: String) -> ResultBox` +- `getNodeId() -> String` +- `isReachable(nodeId: String) -> Bool` +- `getTransportType() -> String` +- `debugNodes() -> String` (inprocess only) +- `debugBusId() -> String` (inprocess only) +- `getLastFrom() -> String` (loopback trace) +- `getLastIntentName() -> String` (loopback trace) + +Notes: +- Handlers currently accept a method reference (`MethodBox`) rather than an inline function literal. +- For quick loopback smoke without handlers, send to self and read `getLast*()`. + +## Quick Smoke (No Handlers) +``` +alice = new P2PBox("alice", "inprocess") +msg = new IntentBox("ping", { }) +res = alice.send("alice", msg) +print("last.from=" + alice.getLastFrom()) +print("last.intent=" + alice.getLastIntentName()) +``` + +## Two-Node Ping-Pong (Concept) +This is covered in unit tests; handler wiring uses `MethodBox` internally. A higher-level sugar for method references will arrive in later phases. + diff --git a/docs_backup_20250820_214047.tar.gz b/docs_backup_20250820_214047.tar.gz deleted file mode 100644 index 7e722fff..00000000 Binary files a/docs_backup_20250820_214047.tar.gz and /dev/null differ diff --git a/examples/p2p_ping_pong.nyash b/examples/p2p_ping_pong.nyash new file mode 100644 index 00000000..00387986 --- /dev/null +++ b/examples/p2p_ping_pong.nyash @@ -0,0 +1,44 @@ +// 📡 P2P Two-Node Ping-Pong (InProcess) +// Uses MethodBox handlers to wire reply path. + +print("🚀 P2P Two-Node Ping-Pong Start") + +// Nodes +alice = new P2PBox("alice", "inprocess") +bob = new P2PBox("bob", "inprocess") + +// Service box to hold node reference and implement handlers +box PingService { + init { node, name } + + onPing(intent, sender) { + print("[" + me.name + "] recv " + intent.getName() + " from " + sender) + // reply pong back + reply = new IntentBox("pong", "{}") + me.node.send(sender, reply) + } + + onPong(intent, sender) { + print("[" + me.name + "] recv " + intent.getName() + " from " + sender) + } +} + +// Wire handlers +svcBob = new PingService() +svcBob.node = bob +svcBob.name = "bob" +bob.on("ping", new MethodBox(svcBob, "onPing")) + +svcAlice = new PingService() +svcAlice.node = alice +svcAlice.name = "alice" +alice.on("pong", new MethodBox(svcAlice, "onPong")) + +// Kick ping +alice.send("bob", new IntentBox("ping", "{}")) + +// Show traces for determinism +print("alice.last=" + alice.getLastIntentName()) +print("bob.last=" + bob.getLastIntentName()) + +print("✅ P2P Two-Node Ping-Pong Done") diff --git a/examples/p2p_self_ping.nyash b/examples/p2p_self_ping.nyash new file mode 100644 index 00000000..15bc912d --- /dev/null +++ b/examples/p2p_self_ping.nyash @@ -0,0 +1,26 @@ +// 📡 P2P Self Ping Smoke +// Purpose: Minimal, deterministic P2PBox demo without external timing. +// Shows send(to=self) loopback traces and universal methods. + +print("🚀 P2P Self Ping Smoke Start") + +// Create node 'alice' on inprocess transport +alice = new P2PBox("alice", "inprocess") + +// Show basic info +print("node=" + alice.getNodeId() + ", transport=" + alice.getTransportType()) + +// Create an IntentBox and send to self +msg = new IntentBox("ping", "{}") +res = alice.send("alice", msg) +print("send result=" + res.toString()) + +// Read back last received traces (populated for self-loop) +print("last.from=" + alice.getLastFrom()) +print("last.intent=" + alice.getLastIntentName()) + +// Show debug helpers +print("nodes=" + alice.debugNodes()) +print("bus=" + alice.debugBusId()) + +print("✅ P2P Self Ping Smoke Done") diff --git a/http_test_log.txt b/http_test_log.txt deleted file mode 100644 index 648f0930..00000000 --- a/http_test_log.txt +++ /dev/null @@ -1,48 +0,0 @@ -HTTP E2Eテスト実行ログ (2025-08-21) -================================ - -【テスト実行コマンド】 -NYASH_NET_LOG=1 cargo test --features plugins --test e2e_plugin_net -- --nocapture - -【テスト結果サマリー】 -- 全5テスト失敗 -- エラー内容: Cannot call method 'respond' on non-instance type (VoidBox) - -【詳細なエラー解析】 - -1. 根本原因: HttpRequestBox作成失敗 - - HttpServerBox.start() → 成功(instance_id作成確認) - - server.accept() → VoidBoxを返す(本来はHttpRequestBoxを返すべき) - - VoidBox.respond() → エラー(VoidBoxにはrespond()メソッドがない) - -2. 主要なログ出力: - - 🎉 birth() success: HttpServerBox instance_id=5 - - 🎉 birth() success: HttpClientBox instance_id=6 - - ❌ Interpreter error: Type error: Cannot call method 'respond' on non-instance type - -3. プラグインシステムの挙動: - - プラグインロード: 成功 - - Box型の認識: 成功(type_id=20 for HttpServerBox等) - - メソッド呼び出し: 部分的成功(start/stopは動作、acceptが問題) - -【失敗したテスト一覧】 -1. e2e_http_stub_end_to_end -2. e2e_http_post_and_headers -3. e2e_http_multiple_requests_order -4. e2e_http_server_restart -5. e2e_http_server_shutdown_and_restart - -【Socket E2Eテストとの比較】 -- Socket E2Eテスト: 全て成功(2/2 passed) -- HTTP E2Eテスト: 全て失敗(0/5 passed) -- 結論: プラグインシステム自体は正常、HTTP実装固有の問題 - -【推測される問題】 -1. HTTP accept()メソッドの実装が未完成(PoC段階) -2. 実際のHTTPリクエスト受信処理が未実装 -3. HttpRequestBoxインスタンスの生成ロジックが欠落 - -【ChatGPT5さんへの報告事項】 -- VoidBoxエラーはaccept()メソッドの戻り値が原因 -- HTTPサーバーの実装は基本的なソケット処理が必要 -- Socket実装は安定しているので参考にできる可能性あり \ No newline at end of file diff --git a/http_test_raw_log.txt b/http_test_raw_log.txt deleted file mode 100644 index bacdee54..00000000 --- a/http_test_raw_log.txt +++ /dev/null @@ -1,459 +0,0 @@ -warning: unused macro definition: `debug_trace` - --> src/interpreter/core.rs:35:14 - | -35 | macro_rules! debug_trace { - | ^^^^^^^^^^^ - | - = note: `#[warn(unused_macros)]` on by default - -warning: unexpected `cfg` condition value: `llvm` - --> src/backend/mod.rs:13:7 - | -13 | #[cfg(feature = "llvm")] - | ^^^^^^^^^^^^^^^^ - | - = note: expected values for `feature` are: `all-examples`, `cli`, `default`, `dynamic-file`, `gui`, `gui-examples`, `plugins`, and `wasm-backend` - = help: consider adding `llvm` as a feature in `Cargo.toml` - = note: see for more information about checking conditional configuration - = note: `#[warn(unexpected_cfgs)]` on by default - -warning: unexpected `cfg` condition value: `llvm` - --> src/backend/mod.rs:23:7 - | -23 | #[cfg(feature = "llvm")] - | ^^^^^^^^^^^^^^^^ - | - = note: expected values for `feature` are: `all-examples`, `cli`, `default`, `dynamic-file`, `gui`, `gui-examples`, `plugins`, and `wasm-backend` - = help: consider adding `llvm` as a feature in `Cargo.toml` - = note: see for more information about checking conditional configuration - -warning: unreachable statement - --> src/interpreter/objects.rs:109:9 - | -27 | / match nyash_args { -28 | | Ok(args) => { -29 | | // Handle generics: if user-defined and type arguments provided, specialize declaration -30 | | let mut target_class = class.to_string(); -... | -106 | | } - | |_________- any code following this `match` expression is unreachable, as all arms diverge -... -109 | return Err(RuntimeError::UndefinedClass { name: class.to_string() }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement - | - = note: `#[warn(unreachable_code)]` on by default - -warning: unreachable pattern - --> src/interpreter/objects.rs:231:13 - | -120 | / "StringBox" | "IntegerBox" | "BoolBox" | "ArrayBox" | "ResultBox" | -121 | | "ErrorBox" | "NullBox" | "FloatBox" | "MapBox" => { - | |__________________________________________________________- matches all the relevant values -... -231 | "NullBox" => { - | ^^^^^^^^^ no value can reach this - | - = note: `#[warn(unreachable_patterns)]` on by default - -warning: unreachable pattern - --> src/interpreter/objects.rs:384:13 - | -120 | / "StringBox" | "IntegerBox" | "BoolBox" | "ArrayBox" | "ResultBox" | -121 | | "ErrorBox" | "NullBox" | "FloatBox" | "MapBox" => { - | |__________________________________________________________- matches all the relevant values -... -384 | "FloatBox" => { - | ^^^^^^^^^^ no value can reach this - -warning: unreachable pattern - --> src/interpreter/objects.rs:484:13 - | -120 | / "StringBox" | "IntegerBox" | "BoolBox" | "ArrayBox" | "ResultBox" | -121 | | "ErrorBox" | "NullBox" | "FloatBox" | "MapBox" => { - | |__________________________________________________________- matches all the relevant values -... -484 | "MapBox" => { - | ^^^^^^^^ no value can reach this - -warning: `nyash-rust` (lib) generated 7 warnings -warning: unexpected `cfg` condition value: `llvm` - --> src/runner.rs:28:7 - | -28 | #[cfg(feature = "llvm")] - | ^^^^^^^^^^^^^^^^ - | - = note: expected values for `feature` are: `all-examples`, `cli`, `default`, `dynamic-file`, `gui`, `gui-examples`, `plugins`, and `wasm-backend` - = help: consider adding `llvm` as a feature in `Cargo.toml` - = note: see for more information about checking conditional configuration - -warning: unexpected `cfg` condition value: `llvm` - --> src/runner.rs:568:15 - | -568 | #[cfg(feature = "llvm")] - | ^^^^^^^^^^^^^^^^ - | - = note: expected values for `feature` are: `all-examples`, `cli`, `default`, `dynamic-file`, `gui`, `gui-examples`, `plugins`, and `wasm-backend` - = help: consider adding `llvm` as a feature in `Cargo.toml` - = note: see for more information about checking conditional configuration - -warning: unexpected `cfg` condition value: `llvm` - --> src/runner.rs:591:19 - | -591 | #[cfg(not(feature = "llvm"))] - | ^^^^^^^^^^^^^^^^ - | - = note: expected values for `feature` are: `all-examples`, `cli`, `default`, `dynamic-file`, `gui`, `gui-examples`, `plugins`, and `wasm-backend` - = help: consider adding `llvm` as a feature in `Cargo.toml` - = note: see for more information about checking conditional configuration - -warning: `nyash-rust` (bin "nyash") generated 3 warnings (1 duplicate) - -running 5 tests -🔍 create_box called for: HttpServerBox -🔍 Config loaded successfully -🔍 create_box called for: HttpServerBox -🔍 Config loaded successfully -🔍 create_box called for: HttpServerBox -🔍 Config loaded successfully -🔍 create_box called for: HttpServerBox -🔍 Config loaded successfully -🔍 create_box called for: HttpServerBox -🔍 Config loaded successfully -🔍 Found library: libnyash_net_plugin.so for box type: HttpServerBox -🔍 Plugin loaded successfully -🔍 Reading nyash.toml for type configuration... -🔍 Found library: libnyash_net_plugin.so for box type: HttpServerBox -🔍 Plugin loaded successfully -🔍 Reading nyash.toml for type configuration... -🔍 Found library: libnyash_net_plugin.so for box type: HttpServerBox -🔍 Plugin loaded successfully -🔍 Reading nyash.toml for type configuration... -🔍 Found library: libnyash_net_plugin.so for box type: HttpServerBox -🔍 Plugin loaded successfully -🔍 Reading nyash.toml for type configuration... -🔍 Found library: libnyash_net_plugin.so for box type: HttpServerBox -🔍 Plugin loaded successfully -🔍 Reading nyash.toml for type configuration... -🔍 nyash.toml read successfully -🔍 nyash.toml read successfully -🔍 nyash.toml read successfully -🔍 nyash.toml read successfully -🔍 nyash.toml read successfully -🔍 nyash.toml parsed successfully -🔍 Found box config for HttpServerBox with type_id: 20 -🔍 Preparing to call birth() with type_id: 20 -🔍 Output buffer allocated, about to call plugin invoke_fn... -🔍 Calling invoke_fn(type_id=20, method_id=0, instance_id=0, tlv_args=[1, 0, 0, 0], output_buf, output_size=1024) -🔍 invoke_fn returned with result: 0 -🎉 birth() success: HttpServerBox instance_id=1 -🔍 DEBUG: PluginBoxV2::share_box called for HttpServerBox (id=1) -🔍 stdlib not initialized for method call -🔍 DEBUG: PluginBoxV2::share_box called for HttpServerBox (id=1) -🔍 DEBUG: execute_method_call - object type: PluginBoxV2, method: start -🔍 DEBUG: Checking StringBox downcast for type: PluginBoxV2 -🔍 DEBUG: StringBox downcast failed -🔍 execute_plugin_box_v2_method called: HttpServerBox.start -[PluginLoaderV2] Invoke HttpServerBox.start: resolving and encoding args (argc=1) -[PluginLoaderV2] arg[0]: Integer(8099) -> Integer(tag=5) -🔍 stdlib not initialized for method call -🔍 nyash.toml parsed successfully -🔍 Found box config for HttpServerBox with type_id: 20 -🔍 Preparing to call birth() with type_id: 20 -🔍 Output buffer allocated, about to call plugin invoke_fn... -🔍 Calling invoke_fn(type_id=20, method_id=0, instance_id=0, tlv_args=[1, 0, 0, 0], output_buf, output_size=1024) -🔍 invoke_fn returned with result: 0 -🎉 birth() success: HttpServerBox instance_id=2 -🔍 DEBUG: PluginBoxV2::share_box called for HttpServerBox (id=2) -🔍 stdlib not initialized for method call -🔍 DEBUG: PluginBoxV2::share_box called for HttpServerBox (id=2) -🔍 DEBUG: execute_method_call - object type: PluginBoxV2, method: start -🔍 DEBUG: Checking StringBox downcast for type: PluginBoxV2 -🔍 DEBUG: StringBox downcast failed -🔍 execute_plugin_box_v2_method called: HttpServerBox.start -[PluginLoaderV2] Invoke HttpServerBox.start: resolving and encoding args (argc=1) -[PluginLoaderV2] arg[0]: Integer(8095) -> Integer(tag=5) -🔍 stdlib not initialized for method call -🔍 nyash.toml parsed successfully -🔍 Found box config for HttpServerBox with type_id: 20 -🔍 Preparing to call birth() with type_id: 20 -🔍 Output buffer allocated, about to call plugin invoke_fn... -🔍 Calling invoke_fn(type_id=20, method_id=0, instance_id=0, tlv_args=[1, 0, 0, 0], output_buf, output_size=1024) -🔍 invoke_fn returned with result: 0 -🎉 birth() success: HttpServerBox instance_id=3 -🔍 DEBUG: PluginBoxV2::share_box called for HttpServerBox (id=3) -🔍 stdlib not initialized for method call -🔍 DEBUG: PluginBoxV2::share_box called for HttpServerBox (id=3) -🔍 DEBUG: execute_method_call - object type: PluginBoxV2, method: start -🔍 DEBUG: Checking StringBox downcast for type: PluginBoxV2 -🔍 DEBUG: StringBox downcast failed -🔍 execute_plugin_box_v2_method called: HttpServerBox.start -[PluginLoaderV2] Invoke HttpServerBox.start: resolving and encoding args (argc=1) -[PluginLoaderV2] arg[0]: Integer(8096) -> Integer(tag=5) -🔍 stdlib not initialized for method call -🔍 nyash.toml parsed successfully -🔍 Found box config for HttpServerBox with type_id: 20 -🔍 Preparing to call birth() with type_id: 20 -🔍 Output buffer allocated, about to call plugin invoke_fn... -🔍 Calling invoke_fn(type_id=20, method_id=0, instance_id=0, tlv_args=[1, 0, 0, 0], output_buf, output_size=1024) -🔍 invoke_fn returned with result: 0 -🎉 birth() success: HttpServerBox instance_id=4 -🔍 DEBUG: PluginBoxV2::share_box called for HttpServerBox (id=4) -🔍 stdlib not initialized for method call -🔍 DEBUG: PluginBoxV2::share_box called for HttpServerBox (id=4) -🔍 DEBUG: execute_method_call - object type: PluginBoxV2, method: start -🔍 DEBUG: Checking StringBox downcast for type: PluginBoxV2 -🔍 DEBUG: StringBox downcast failed -🔍 execute_plugin_box_v2_method called: HttpServerBox.start -[PluginLoaderV2] Invoke HttpServerBox.start: resolving and encoding args (argc=1) -[PluginLoaderV2] arg[0]: Integer(8097) -> Integer(tag=5) -🔍 stdlib not initialized for method call -🔍 nyash.toml parsed successfully -🔍 Found box config for HttpServerBox with type_id: 20 -🔍 Preparing to call birth() with type_id: 20 -🔍 Output buffer allocated, about to call plugin invoke_fn... -🔍 Calling invoke_fn(type_id=20, method_id=0, instance_id=0, tlv_args=[1, 0, 0, 0], output_buf, output_size=1024) -🔍 invoke_fn returned with result: 0 -🎉 birth() success: HttpServerBox instance_id=5 -🔍 DEBUG: PluginBoxV2::share_box called for HttpServerBox (id=5) -🔍 stdlib not initialized for method call -🔍 DEBUG: PluginBoxV2::share_box called for HttpServerBox (id=5) -🔍 DEBUG: execute_method_call - object type: PluginBoxV2, method: start -🔍 DEBUG: Checking StringBox downcast for type: PluginBoxV2 -🔍 DEBUG: StringBox downcast failed -🔍 execute_plugin_box_v2_method called: HttpServerBox.start -[PluginLoaderV2] Invoke HttpServerBox.start: resolving and encoding args (argc=1) -[PluginLoaderV2] arg[0]: Integer(8098) -> Integer(tag=5) -🔍 stdlib not initialized for method call -🔍 create_box called for: HttpClientBox -🔍 Config loaded successfully -🔍 create_box called for: HttpClientBox -🔍 Config loaded successfully -🔍 create_box called for: HttpClientBox -🔍 Config loaded successfully -🔍 Found library: libnyash_net_plugin.so for box type: HttpClientBox -🔍 Plugin loaded successfully -🔍 Reading nyash.toml for type configuration... -🔍 Found library: libnyash_net_plugin.so for box type: HttpClientBox -🔍 Plugin loaded successfully -🔍 Reading nyash.toml for type configuration... -🔍 Found library: libnyash_net_plugin.so for box type: HttpClientBox -🔍 Plugin loaded successfully -🔍 Reading nyash.toml for type configuration... -🔍 nyash.toml read successfully -🔍 nyash.toml read successfully -🔍 nyash.toml read successfully -🔍 DEBUG: execute_method_call - object type: PluginBoxV2, method: accept -🔍 DEBUG: Checking StringBox downcast for type: PluginBoxV2 -🔍 DEBUG: StringBox downcast failed -🔍 execute_plugin_box_v2_method called: HttpServerBox.accept -[PluginLoaderV2] Invoke HttpServerBox.accept: resolving and encoding args (argc=0) -🔍 stdlib not initialized for method call -🔍 DEBUG: execute_method_call - object type: PluginBoxV2, method: accept -🔍 DEBUG: Checking StringBox downcast for type: PluginBoxV2 -🔍 DEBUG: StringBox downcast failed -🔍 execute_plugin_box_v2_method called: HttpServerBox.accept -[PluginLoaderV2] Invoke HttpServerBox.accept: resolving and encoding args (argc=0) -🔍 stdlib not initialized for method call -🔍 DEBUG: execute_method_call - object type: PluginBoxV2, method: accept -🔍 DEBUG: Checking StringBox downcast for type: PluginBoxV2 -🔍 DEBUG: StringBox downcast failed -🔍 execute_plugin_box_v2_method called: HttpServerBox.accept -[PluginLoaderV2] Invoke HttpServerBox.accept: resolving and encoding args (argc=0) -🔍 stdlib not initialized for method call -🔍 DEBUG: execute_method_call - object type: PluginBoxV2, method: accept -🔍 DEBUG: Checking StringBox downcast for type: PluginBoxV2 -🔍 DEBUG: StringBox downcast failed -🔍 execute_plugin_box_v2_method called: HttpServerBox.accept -[PluginLoaderV2] Invoke HttpServerBox.accept: resolving and encoding args (argc=0) -🔍 stdlib not initialized for method call -🔍 DEBUG: execute_method_call - object type: PluginBoxV2, method: accept -🔍 DEBUG: Checking StringBox downcast for type: PluginBoxV2 -🔍 DEBUG: StringBox downcast failed -🔍 execute_plugin_box_v2_method called: HttpServerBox.accept -[PluginLoaderV2] Invoke HttpServerBox.accept: resolving and encoding args (argc=0) -🔍 stdlib not initialized for method call -🔍 nyash.toml parsed successfully -🔍 Found box config for HttpClientBox with type_id: 23 -🔍 Preparing to call birth() with type_id: 23 -🔍 Output buffer allocated, about to call plugin invoke_fn... -🔍 Calling invoke_fn(type_id=23, method_id=0, instance_id=0, tlv_args=[1, 0, 0, 0], output_buf, output_size=1024) -🔍 invoke_fn returned with result: 0 -🎉 birth() success: HttpClientBox instance_id=6 -🔍 DEBUG: PluginBoxV2::share_box called for HttpClientBox (id=6) -🔍 stdlib not initialized for method call -🔍 DEBUG: PluginBoxV2::share_box called for HttpClientBox (id=6) -🔍 DEBUG: execute_method_call - object type: PluginBoxV2, method: get -🔍 DEBUG: Checking StringBox downcast for type: PluginBoxV2 -🔍 DEBUG: StringBox downcast failed -🔍 execute_plugin_box_v2_method called: HttpClientBox.get -[PluginLoaderV2] Invoke HttpClientBox.get: resolving and encoding args (argc=1) -[PluginLoaderV2] arg[0]: String(len=27) -> String(tag=6) -🔍 stdlib not initialized for method call -🔍 nyash.toml parsed successfully -🔍 Found box config for HttpClientBox with type_id: 23 -🔍 Preparing to call birth() with type_id: 23 -🔍 Output buffer allocated, about to call plugin invoke_fn... -🔍 Calling invoke_fn(type_id=23, method_id=0, instance_id=0, tlv_args=[1, 0, 0, 0], output_buf, output_size=1024) -🔍 invoke_fn returned with result: 0 -🎉 birth() success: HttpClientBox instance_id=7 -🔍 DEBUG: PluginBoxV2::share_box called for HttpClientBox (id=7) -🔍 stdlib not initialized for method call -🔍 DEBUG: PluginBoxV2::share_box called for HttpClientBox (id=7) -🔍 DEBUG: execute_method_call - object type: PluginBoxV2, method: post -🔍 DEBUG: Checking StringBox downcast for type: PluginBoxV2 -🔍 DEBUG: StringBox downcast failed -🔍 execute_plugin_box_v2_method called: HttpClientBox.post -[PluginLoaderV2] Invoke HttpClientBox.post: resolving and encoding args (argc=2) -[PluginLoaderV2] arg[0]: String(len=35) -> String(tag=6) -[PluginLoaderV2] arg[1]: String(len=15) -> String(tag=6) -🔍 stdlib not initialized for method call -🔍 nyash.toml parsed successfully -🔍 Found box config for HttpClientBox with type_id: 23 -🔍 Preparing to call birth() with type_id: 23 -🔍 Output buffer allocated, about to call plugin invoke_fn... -🔍 Calling invoke_fn(type_id=23, method_id=0, instance_id=0, tlv_args=[1, 0, 0, 0], output_buf, output_size=1024) -🔍 invoke_fn returned with result: 0 -🎉 birth() success: HttpClientBox instance_id=8 -🔍 DEBUG: PluginBoxV2::share_box called for HttpClientBox (id=8) -🔍 stdlib not initialized for method call -🔍 DEBUG: PluginBoxV2::share_box called for HttpClientBox (id=8) -🔍 DEBUG: execute_method_call - object type: PluginBoxV2, method: get -🔍 DEBUG: Checking StringBox downcast for type: PluginBoxV2 -🔍 DEBUG: StringBox downcast failed -🔍 execute_plugin_box_v2_method called: HttpClientBox.get -[PluginLoaderV2] Invoke HttpClientBox.get: resolving and encoding args (argc=1) -[PluginLoaderV2] arg[0]: String(len=21) -> String(tag=6) -🔍 stdlib not initialized for method call -🔍 Plugin invoke completed with result: 0 -🔍 plugin_invoke_v2 returned result: 0 -🔍 TLV output from plugin (len=4): [1, 0, 0, 0] -🔍 Plugin invoke completed with result: 0 -🔍 plugin_invoke_v2 returned result: 0 -🔍 TLV output from plugin (len=4): [1, 0, 0, 0] -🔍 Plugin invoke completed with result: 0 -🔍 plugin_invoke_v2 returned result: 0 -🔍 TLV output from plugin (len=4): [1, 0, 0, 0] -🔍 Plugin invoke completed with result: 0 -🔍 plugin_invoke_v2 returned result: 0 -🔍 TLV output from plugin (len=4): [1, 0, 0, 0] -🔍 Plugin invoke completed with result: 0 -🔍 plugin_invoke_v2 returned result: 0 -🔍 TLV output from plugin (len=4): [1, 0, 0, 0] -🔍 Plugin invoke completed with result: 0 -🔍 plugin_invoke_v2 returned result: 0 -🔍 TLV output from plugin (len=4): [1, 0, 0, 0] -🔍 Plugin invoke completed with result: 0 -🔍 plugin_invoke_v2 returned result: 0 -🔍 TLV output from plugin (len=4): [1, 0, 0, 0] -🔍 Plugin invoke completed with result: 0 -🔍 plugin_invoke_v2 returned result: 0 -🔍 TLV output from plugin (len=4): [1, 0, 0, 0] -🔍 create_box called for: VoidBox -VoidBox is not a plugin box type -🔍 DEBUG: execute_method_call - object type: VoidBox, method: respond -🔍 DEBUG: Checking StringBox downcast for type: VoidBox -🔍 DEBUG: StringBox downcast failed -🔍 DEBUG: Reached non-instance type error for type: VoidBox, method: respond -❌ Interpreter error: Type error: Cannot call method 'respond' on non-instance type -🔍 create_box called for: VoidBox -VoidBox is not a plugin box type -🔍 create_box called for: VoidBox -VoidBox is not a plugin box type -🔍 DEBUG: execute_method_call - object type: VoidBox, method: readBody -🔍 DEBUG: Checking StringBox downcast for type: VoidBox -🔍 DEBUG: StringBox downcast failed -🔍 DEBUG: Reached non-instance type error for type: VoidBox, method: readBody -❌ Interpreter error: Type error: Cannot call method 'readBody' on non-instance type -🔍 create_box called for: HttpResponseBox -🔍 Config loaded successfully -🔍 create_box called for: HttpResponseBox -🔍 Config loaded successfully - -thread 'e2e_http_post_and_headers' panicked at tests/e2e_plugin_net.rs:159:43: -exec failed: TypeError { message: "Cannot call method 'readBody' on non-instance type" } -🔍 Found library: libnyash_net_plugin.so for box type: HttpResponseBox -🔍 Plugin loaded successfully -🔍 Reading nyash.toml for type configuration... -🔍 Found library: libnyash_net_plugin.so for box type: HttpResponseBox -🔍 Plugin loaded successfully -🔍 Reading nyash.toml for type configuration... -🔍 nyash.toml read successfully -🔍 nyash.toml read successfully -🔍 nyash.toml parsed successfully -🔍 Found box config for HttpResponseBox with type_id: 22 -🔍 Preparing to call birth() with type_id: 22 -🔍 Output buffer allocated, about to call plugin invoke_fn... -🔍 Calling invoke_fn(type_id=22, method_id=0, instance_id=0, tlv_args=[1, 0, 0, 0], output_buf, output_size=1024) -🔍 invoke_fn returned with result: 0 -🎉 birth() success: HttpResponseBox instance_id=9 -🔍 DEBUG: PluginBoxV2::share_box called for HttpResponseBox (id=9) -🔍 stdlib not initialized for method call -🔍 DEBUG: PluginBoxV2::share_box called for HttpResponseBox (id=9) -🔍 DEBUG: execute_method_call - object type: PluginBoxV2, method: write -🔍 DEBUG: Checking StringBox downcast for type: PluginBoxV2 -🔍 DEBUG: StringBox downcast failed -🔍 execute_plugin_box_v2_method called: HttpResponseBox.write -🔍 nyash.toml parsed successfully -🔍 Found box config for HttpResponseBox with type_id: 22 -🔍 Preparing to call birth() with type_id: 22 -🔍 Output buffer allocated, about to call plugin invoke_fn... -🔍 Calling invoke_fn(type_id=22, method_id=0, instance_id=0, tlv_args=[1, 0, 0, 0], output_buf, output_size=1024) -🔍 invoke_fn returned with result: 0 -🎉 birth() success: HttpResponseBox instance_id=10 -🔍 DEBUG: PluginBoxV2::share_box called for HttpResponseBox (id=10) -🔍 stdlib not initialized for method call -🔍 DEBUG: PluginBoxV2::share_box called for HttpResponseBox (id=10) -🔍 DEBUG: execute_method_call - object type: PluginBoxV2, method: write -🔍 DEBUG: Checking StringBox downcast for type: PluginBoxV2 -🔍 DEBUG: StringBox downcast failed -🔍 execute_plugin_box_v2_method called: HttpResponseBox.write -🔍 DEBUG: execute_method_call - object type: VoidBox, method: path -🔍 DEBUG: Checking StringBox downcast for type: VoidBox -🔍 DEBUG: StringBox downcast failed -🔍 DEBUG: Reached non-instance type error for type: VoidBox, method: path -❌ Interpreter error: Type error: Cannot call method 'path' on non-instance type - -thread 'e2e_http_multiple_requests_order' panicked at tests/e2e_plugin_net.rs:186:43: -exec failed: TypeError { message: "Cannot call method 'path' on non-instance type" } -[PluginLoaderV2] Invoke HttpResponseBox.write: resolving and encoding args (argc=1) -[PluginLoaderV2] arg[0]: String(len=1) -> String(tag=6) -🔍 stdlib not initialized for method call -[PluginLoaderV2] Invoke HttpResponseBox.write: resolving and encoding args (argc=1) -[PluginLoaderV2] arg[0]: String(len=1) -> String(tag=6) -🔍 stdlib not initialized for method call -🔍 DEBUG: execute_method_call - object type: VoidBox, method: respond -🔍 DEBUG: Checking StringBox downcast for type: VoidBox -🔍 DEBUG: StringBox downcast failed -🔍 DEBUG: Reached non-instance type error for type: VoidBox, method: respond -🔍 DEBUG: execute_method_call - object type: VoidBox, method: respond -🔍 DEBUG: Checking StringBox downcast for type: VoidBox -🔍 DEBUG: StringBox downcast failed -🔍 DEBUG: Reached non-instance type error for type: VoidBox, method: respond -❌ Interpreter error: Type error: Cannot call method 'respond' on non-instance type -❌ Interpreter error: Type error: Cannot call method 'respond' on non-instance type - -thread 'e2e_http_server_shutdown_and_restart' panicked at tests/e2e_plugin_net.rs:102:22: -exec1: TypeError { message: "Cannot call method 'respond' on non-instance type" } - -thread 'e2e_http_server_restart' panicked at tests/e2e_plugin_net.rs:80:43: -exec failed: TypeError { message: "Cannot call method 'respond' on non-instance type" } -error: test failed, to rerun pass `--test e2e_plugin_net` - - -running 5 tests -test e2e_http_stub_end_to_end ... FAILED -test e2e_http_post_and_headers ... FAILED -test e2e_http_multiple_requests_order ... FAILED -test e2e_http_server_shutdown_and_restart ... FAILED -test e2e_http_server_restart ... FAILED - -failures: - -failures: - e2e_http_multiple_requests_order - e2e_http_post_and_headers - e2e_http_server_restart - e2e_http_server_shutdown_and_restart - e2e_http_stub_end_to_end - -test result: FAILED. 0 passed; 5 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.81s \ No newline at end of file diff --git a/mir_error.txt b/mir_error.txt deleted file mode 100644 index 0cae45e9..00000000 --- a/mir_error.txt +++ /dev/null @@ -1,57 +0,0 @@ -🔍 DEBUG: Initializing v2 plugin system -[FileBox] Plugin initialized -🔌 v2 plugin system initialized from nyash.toml - 📦 Registering plugin provider for FileBox -✅ v2 plugin system fully configured -🚀 Nyash MIR Compiler - Processing file: docs/examples/visibility_error.nyash 🚀 -🚀 MIR Output for docs/examples/visibility_error.nyash: -; MIR Module: main - -define void @User.birth/2(box %0, ? %1, ? %2) effects(read) { -bb1: - 0: ref_set %0.name = %1 - 1: ref_set %0.age = %2 - 2: %3 = const void - 3: ret %3 -} - -define void @main() { -bb0: - 0: safepoint - 1: %0 = const "__me__" - 2: %1 = new ConsoleBox() - 3: call %1.birth() - 4: ref_set %0.console = %1 - 5: %2 = const "__box_type_User" - 6: %3 = const "__field_User_age" - 7: %4 = const "__field_User_passwordHash" - 8: %5 = const "__field_User_name" - 9: %6 = const void - 10: %7 = const "Alice" - 11: %8 = new StringBox(%7) - 12: call %8.birth(%7) - 13: %9 = const 20 - 14: %10 = new IntegerBox(%9) - 15: call %10.birth(%9) - 16: %11 = new User(%8, %10) - 17: call %11.birth(%8, %10) - 18: %12 = const "__me__" - 19: %13 = ref_get %12.console - 20: %14 = const "name(public)=" - 21: %15 = new StringBox(%14) - 22: call %15.birth(%14) - 23: %16 = ref_get %11.name - 24: %17 = %15 Add %16 - 25: %18 = call %13.log(%17) - 26: %19 = const 30 - 27: %20 = new IntegerBox(%19) - 28: call %20.birth(%19) - 29: ref_set %11.age = %20 - 30: %21 = const "__me__" - 31: %22 = ref_get %21.console - 32: %23 = ref_get %11.age - 33: %24 = call %22.log(%23) - 34: ret %24 -} - - diff --git a/mir_ok.txt b/mir_ok.txt deleted file mode 100644 index 64f5a7d0..00000000 --- a/mir_ok.txt +++ /dev/null @@ -1,91 +0,0 @@ -🔍 DEBUG: Initializing v2 plugin system -[FileBox] Plugin initialized -🔌 v2 plugin system initialized from nyash.toml - 📦 Registering plugin provider for FileBox -✅ v2 plugin system fully configured -🚀 Nyash MIR Compiler - Processing file: docs/examples/visibility_ok.nyash 🚀 -🚀 MIR Output for docs/examples/visibility_ok.nyash: -; MIR Module: main - -define void @User.birth/2(box %0, ? %1, ? %2) effects(read) { -bb1: - 0: ref_set %0.name = %1 - 1: ref_set %0.age = %2 - 2: %3 = const void - 3: ret %3 -} - -define void @User.setAge/1(box %0, ? %1) effects(read) { -bb3: - 0: ref_set %0.age = %1 - 1: %2 = const void - 2: ret %2 -} - -define ? @User.getAge/0(box %0) effects(read) { -bb2: - 0: %1 = ref_get %0.age - 1: ret %1 -} - -define void @main() { -bb0: - 0: safepoint - 1: %0 = const "__me__" - 2: %1 = new ConsoleBox() - 3: call %1.birth() - 4: ref_set %0.console = %1 - 5: %2 = const "__box_type_User" - 6: %3 = const "__field_User_age" - 7: %4 = const "__field_User_passwordHash" - 8: %5 = const "__field_User_name" - 9: %6 = const "__method_User_getAge" - 10: %7 = const "__method_User_setAge" - 11: %8 = const void - 12: %9 = const "Alice" - 13: %10 = new StringBox(%9) - 14: call %10.birth(%9) - 15: %11 = const 20 - 16: %12 = new IntegerBox(%11) - 17: call %12.birth(%11) - 18: %13 = new User(%10, %12) - 19: call %13.birth(%10, %12) - 20: %14 = const "__me__" - 21: %15 = ref_get %14.console - 22: %16 = const "name(public)=" - 23: %17 = new StringBox(%16) - 24: call %17.birth(%16) - 25: %18 = ref_get %13.name - 26: %19 = %17 Add %18 - 27: %20 = call %15.log(%19) - 28: %21 = const "Bob" - 29: %22 = new StringBox(%21) - 30: call %22.birth(%21) - 31: ref_set %13.name = %22 - 32: %23 = const "__me__" - 33: %24 = ref_get %23.console - 34: %25 = const "age(private, internal)=" - 35: %26 = new StringBox(%25) - 36: call %26.birth(%25) - 37: %28 = const "User.getAge/0" - 38: %27 = call %28(%13) - 39: %29 = %26 Add %27 - 40: %30 = call %24.log(%29) - 41: %31 = const 21 - 42: %32 = new IntegerBox(%31) - 43: call %32.birth(%31) - 44: %33 = const 21 - 45: %34 = new IntegerBox(%33) - 46: call %34.birth(%33) - 47: %36 = const "User.setAge/1" - 48: %35 = call %36(%13, %34) - 49: %37 = const "__me__" - 50: %38 = ref_get %37.console - 51: %39 = const "done" - 52: %40 = new StringBox(%39) - 53: call %40.birth(%39) - 54: %41 = call %38.log(%40) - 55: ret %41 -} - - diff --git a/nekocode_deadcode_external.json b/nekocode_deadcode_external.json deleted file mode 100644 index 79cafa04..00000000 --- a/nekocode_deadcode_external.json +++ /dev/null @@ -1,2 +0,0 @@ -🔍 Analyzing dead code in session: 86fc6615 -✅ Using external tools for high-accuracy analysis (90%+ confidence) diff --git a/nyash.toml.backup_duplicate b/nyash.toml.backup_duplicate deleted file mode 100644 index 04ff888d..00000000 --- a/nyash.toml.backup_duplicate +++ /dev/null @@ -1,215 +0,0 @@ -# Nyash Configuration File v2 -# マルチBox型プラグイン対応 - -[libraries] -# ライブラリ定義(1つのプラグインで複数のBox型を提供可能) -[libraries."libnyash_filebox_plugin.so"] -boxes = ["FileBox"] -path = "./plugins/nyash-filebox-plugin/target/release/libnyash_filebox_plugin.so" - -[libraries."libnyash_counter_plugin.so"] -boxes = ["CounterBox"] -path = "./plugins/nyash-counter-plugin/target/release/libnyash_counter_plugin.so" - -[libraries."libnyash_net_plugin.so"] -boxes = ["HttpServerBox", "HttpClientBox", "HttpResponseBox", "HttpRequestBox", "SocketServerBox", "SocketClientBox"] -path = "./plugins/nyash-net-plugin/target/release/libnyash_net_plugin.so" - -# 将来の拡張例: -# "libnyash_database_plugin.so" = { -# boxes = ["PostgreSQLBox", "MySQLBox", "SQLiteBox"], -# path = "./target/release/libnyash_database_plugin.so" -# } - -# FileBoxの型情報定義 -[libraries."libnyash_filebox_plugin.so".FileBox] -type_id = 6 - -[libraries."libnyash_filebox_plugin.so".FileBox.methods] -# 全メソッドをmethod_idと共に定義 -birth = { method_id = 0 } -open = { method_id = 1, args = ["path", "mode"] } -read = { method_id = 2 } -write = { method_id = 3, args = ["data"] } -close = { method_id = 4 } -fini = { method_id = 4294967295 } - -# v2.1: Box引数を受け取るメソッド宣言(FileBox: copyFrom(other: Handle)) -copyFrom = { method_id = 7, args = [ { kind = "box", category = "plugin" } ] } - -# v2.2: BoxRef(Handle)を返すメソッド宣言 -cloneSelf = { method_id = 8 } - -[libraries."libnyash_counter_plugin.so".CounterBox] -type_id = 7 -singleton = true - -[libraries."libnyash_counter_plugin.so".CounterBox.methods] -birth = { method_id = 0 } -inc = { method_id = 1 } -get = { method_id = 2 } -fini = { method_id = 4294967295 } - -# HttpServerBox -[libraries."libnyash_net_plugin.so".HttpServerBox] -type_id = 10 - -[libraries."libnyash_net_plugin.so".HttpServerBox.methods] -birth = { method_id = 0 } -start = { method_id = 1, args = ["port"], returns_result = true } -stop = { method_id = 2, returns_result = true } -accept = { method_id = 3, returns_result = true } -fini = { method_id = 4294967295 } - -# HttpClientBox -[libraries."libnyash_net_plugin.so".HttpClientBox] -type_id = 11 - -[libraries."libnyash_net_plugin.so".HttpClientBox.methods] -birth = { method_id = 0 } -get = { method_id = 1, args = ["url"] } -post = { method_id = 2, args = ["url", "body"] } -fini = { method_id = 4294967295 } - -# HttpResponseBox -[libraries."libnyash_net_plugin.so".HttpResponseBox] -type_id = 12 - -[libraries."libnyash_net_plugin.so".HttpResponseBox.methods] -birth = { method_id = 0 } -setStatus = { method_id = 1, args = ["status"] } -setHeader = { method_id = 2, args = ["key", "value"] } -write = { method_id = 3, args = ["body"] } -readBody = { method_id = 4 } -getStatus = { method_id = 5 } -getHeader = { method_id = 6, args = ["key"] } -fini = { method_id = 4294967295 } - -# HttpRequestBox -[libraries."libnyash_net_plugin.so".HttpRequestBox] -type_id = 13 - -[libraries."libnyash_net_plugin.so".HttpRequestBox.methods] -birth = { method_id = 0 } -respond = { method_id = 1, args = [{ kind = "box", category = "plugin" }] } -path = { method_id = 2 } -readBody = { method_id = 3 } -fini = { method_id = 4294967295 } - -# SocketServerBox -[libraries."libnyash_net_plugin.so".SocketServerBox] -type_id = 14 - -[libraries."libnyash_net_plugin.so".SocketServerBox.methods] -birth = { method_id = 0 } -bind = { method_id = 1, args = ["port"] } -accept = { method_id = 2 } -fini = { method_id = 4294967295 } - -# SocketClientBox -[libraries."libnyash_net_plugin.so".SocketClientBox] -type_id = 15 - -[libraries."libnyash_net_plugin.so".SocketClientBox.methods] -birth = { method_id = 0 } -connect = { method_id = 1, args = ["host", "port"] } -send = { method_id = 2, args = ["data"] } -receive = { method_id = 3 } -close = { method_id = 4 } -fini = { method_id = 4294967295 } - -[plugin_paths] -# プラグインの検索パス(デフォルト) -search_paths = [ - "./target/release", - "./target/debug", - "./plugins/*/target/release", - "./plugins/*/target/debug", - "/usr/local/lib/nyash/plugins", - "~/.nyash/plugins" -] -[libraries."libnyash_net_plugin.so"] -boxes = ["HttpServerBox", "HttpRequestBox", "HttpResponseBox", "HttpClientBox", "SocketServerBox", "SocketClientBox", "SocketConnBox"] -path = "./plugins/nyash-net-plugin/target/release/libnyash_net_plugin.so" - -[libraries."libnyash_net_plugin.so".HttpServerBox] -type_id = 20 - -[libraries."libnyash_net_plugin.so".HttpServerBox.methods] -birth = { method_id = 0 } -start = { method_id = 1, args = ["port"], returns_result = true } -stop = { method_id = 2, returns_result = true } -accept = { method_id = 3, returns_result = true } -fini = { method_id = 4294967295 } - -[libraries."libnyash_net_plugin.so".HttpRequestBox] -type_id = 21 - -[libraries."libnyash_net_plugin.so".HttpRequestBox.methods] -birth = { method_id = 0 } -path = { method_id = 1 } -readBody = { method_id = 2 } -respond = { method_id = 3, args = [ { kind = "box", category = "plugin" } ] } -fini = { method_id = 4294967295 } - -[libraries."libnyash_net_plugin.so".HttpResponseBox] -type_id = 22 - -[libraries."libnyash_net_plugin.so".HttpResponseBox.methods] -birth = { method_id = 0 } -setStatus = { method_id = 1 } -setHeader = { method_id = 2 } -write = { method_id = 3 } -readBody = { method_id = 4 } -getStatus = { method_id = 5 } -getHeader = { method_id = 6, args = ["name"] } -fini = { method_id = 4294967295 } - -[libraries."libnyash_net_plugin.so".HttpClientBox] -type_id = 23 - -[libraries."libnyash_net_plugin.so".HttpClientBox.methods] -birth = { method_id = 0 } -get = { method_id = 1, returns_result = true } -post = { method_id = 2, returns_result = true } -fini = { method_id = 4294967295 } - -## ResultBox normalization enabled above for get/post - -[libraries."libnyash_net_plugin.so".SocketServerBox] -type_id = 30 - -[libraries."libnyash_net_plugin.so".SocketServerBox.methods] -birth = { method_id = 0 } -start = { method_id = 1, args = ["port"], returns_result = true } -stop = { method_id = 2, returns_result = true } -accept = { method_id = 3, returns_result = true } -acceptTimeout = { method_id = 4, args = ["timeout_ms"], returns_result = true } -fini = { method_id = 4294967295 } - -# Optional: ResultBox normalization (recommendation) -# start = { method_id = 1, args = ["port"], returns_result = true } -# stop = { method_id = 2, returns_result = true } -# accept = { method_id = 3, returns_result = true } - -[libraries."libnyash_net_plugin.so".SocketClientBox] -type_id = 32 - -[libraries."libnyash_net_plugin.so".SocketClientBox.methods] -birth = { method_id = 0 } -connect = { method_id = 1, args = ["host", "port"], returns_result = true } -fini = { method_id = 4294967295 } - -# Optional: ResultBox normalization (recommendation) -# connect = { method_id = 1, args = ["host", "port"], returns_result = true } - -[libraries."libnyash_net_plugin.so".SocketConnBox] -type_id = 31 - -[libraries."libnyash_net_plugin.so".SocketConnBox.methods] -birth = { method_id = 0 } -send = { method_id = 1 } -recv = { method_id = 2 } -close = { method_id = 3 } -recvTimeout = { method_id = 4, args = ["timeout_ms"], returns_result = true } -fini = { method_id = 4294967295 } diff --git a/private/challenges/ai-agent-challenge-strategy.md b/private/challenges/ai-agent-challenge-strategy.md deleted file mode 100644 index 22e1eecb..00000000 --- a/private/challenges/ai-agent-challenge-strategy.md +++ /dev/null @@ -1,62 +0,0 @@ -# AI Agent Challenge 1日実装戦略 - -## 概要 -DEV.toのAI Agents Challenge(n8n + Bright Data)にNyashで参加する戦略。 -締切: 2025年8月31日 - -## 重要な発見 -- 他の参加者は普通にJavaScriptで実装している(WASMは不要だった!) -- n8nはノーコードツール、Webhookで簡単に連携可能 -- NetBoxプラグインが既にHTTP機能を提供 - -## 1日実装プラン - -### タイムライン -- 8:00-10:00: 基本設計・n8n理解 -- 10:00-13:00: Nyash実装(HTTPBox活用) -- 13:00-16:00: n8n連携・Bright Data統合 -- 16:00-19:00: デモアプリ完成 -- 19:00-21:00: 記事作成・動画録画 -- 21:00-23:00: 投稿・最終調整 - -### 実装アーキテクチャ -```nyash -// n8nブリッジ -box N8nBridge { - init { httpClient, workflows } - - triggerWorkflow(webhookUrl, data) { - return me.httpClient.post(webhookUrl, data) - } -} - -// 価格監視AIエージェント例 -box PriceMonitorAgent { - init { products, notifier } - - monitorPrices() { - // Bright Data経由でスクレイピング - // n8n経由で通知 - } -} -``` - -### 差別化ポイント -1. **Nyashという独自言語**での実装(創造性満点) -2. Everything is Box哲学によるエレガントな設計 -3. 既存のNetBoxプラグインを活用した高速開発 - -### 必要な準備 -- n8n無料アカウント作成 -- Bright Data $250クレジット取得 -- NetBoxプラグインのテスト修正完了 - -### リスクと対策 -- 時間制約 → シンプルな実装に集中 -- 技術学習 → Webhook連携のみに限定 -- デモ作成 → 録画で対応(ライブ不要) - -## 結論 -技術的には1日で実装可能。Nyashの知名度向上と$1,000の賞金獲得のチャンス。 - -最終更新: 2025-08-21 \ No newline at end of file diff --git a/private/challenges/midnight-network-privacy-challenge.md b/private/challenges/midnight-network-privacy-challenge.md deleted file mode 100644 index 9dbc491b..00000000 --- a/private/challenges/midnight-network-privacy-challenge.md +++ /dev/null @@ -1,133 +0,0 @@ -# Midnight Network Privacy-First Challenge 戦略 - -## 🎯 チャレンジ概要 -- **主催**: DEV.to × Midnight Network -- **賞金総額**: $5,000 -- **締切**: 2025年9月7日 11:59 PM PDT -- **発表**: 2025年9月18日 - -## 🏆 カテゴリーと賞金 -1. **"Protect That Data"** - $3,500 - - プライバシー保護アプリケーション - - ゼロ知識証明を活用したソリューション - -2. **"Enhance the Ecosystem"** - $1,000 - - 開発者ツール・SDK - - Midnight開発体験の改善 - -3. **"Best Tutorial"** - $500 - - 教育コンテンツ - - Midnight技術の解説 - -## 💡 Nyashでの参加アイデア - -### 1. **NyashPrivacyBox** - ゼロ知識証明ラッパー(Protect That Data部門) -```nyash -// Midnight NetworkのCompact言語をNyashから使いやすくするBox -box PrivacyBox { - init { midnightClient, proofs } - - // プライベートデータの証明生成 - proveAge(actualAge, minimumAge) { - // ゼロ知識証明で「最低年齢以上」を証明 - // 実際の年齢は公開しない - return me.midnightClient.generateProof({ - "statement": "age >= " + minimumAge, - "witness": actualAge - }) - } - - // プライベート投票システム - vote(choice) { - // 投票内容を秘密にしたまま、有効な投票であることを証明 - local proof = me.midnightClient.proveValidVote(choice) - return me.submitVote(proof) - } -} -``` - -### 2. **Nyash→Compact トランスパイラー** (Enhance the Ecosystem部門) -```nyash -// NyashコードをMidnight Compact言語に変換 -box CompactTranspiler { - transpile(nyashCode) { - // Everything is Box → Compact型システム - // Nyashのプライバシー宣言をCompactに変換 - return me.convertToCompact(nyashCode) - } -} -``` - -### 3. **インタラクティブZKPチュートリアル** (Best Tutorial部門) -- Nyashで書かれたステップバイステップガイド -- ブラウザ上で動作するWASM版デモ -- ゼロ知識証明の概念を視覚的に解説 - -## 🛠️ 技術要件 -- **Midnight Compact言語**: プライバシー保護言語 -- **MidnightJS**: JavaScript SDK -- **Apache 2.0ライセンス**: オープンソース必須 -- **GitHub公開**: リポジトリ必須 - -## 📅 実装計画(〜9月7日) - -### Phase 1: 調査(8月24-26日) -- [ ] Midnight Networkドキュメント熟読 -- [ ] Compact言語の基礎学習 -- [ ] MidnightJSのサンプル実行 - -### Phase 2: プロトタイプ(8月27-31日) -- [ ] NyashからMidnightJSを呼び出す基本実装 -- [ ] PrivacyBoxの最小実装 -- [ ] 簡単なゼロ知識証明デモ - -### Phase 3: 本実装(9月1-5日) -- [ ] 選択したカテゴリーの実装完成 -- [ ] ドキュメント作成 -- [ ] デモアプリケーション - -### Phase 4: 仕上げ(9月6-7日) -- [ ] チュートリアル動画作成 -- [ ] 最終テスト -- [ ] 提出準備 - -## 🎯 戦略的優位性 - -### Nyashの強み -1. **Everything is Box哲学** - - プライバシーもBoxとして扱える - - 直感的なAPIデザイン - -2. **WASM対応** - - ブラウザでゼロ知識証明デモ可能 - - インタラクティブな教育コンテンツ - -3. **独自性** - - Nyashという新言語での実装は注目を集める - - 審査員の記憶に残りやすい - -## 🤔 検討事項 - -### 技術的課題 -- MidnightJSとの統合方法 -- Compact言語の学習曲線 -- ゼロ知識証明の実装複雑性 - -### 時間的制約 -- 約2週間での実装 -- Midnight技術の学習時間 -- ドキュメント・チュートリアル作成 - -## 🎬 次のステップ - -1. **今すぐ**: Midnight Networkのアカウント作成 -2. **明日**: Compact言語チュートリアル開始 -3. **週末**: 最初のプロトタイプ作成 - -## 📚 参考リンク -- [Midnight Developer Docs](https://docs.midnight.network/) -- [Challenge Details](https://dev.to/devteam/join-the-midnight-network-privacy-first-challenge-5000-in-prizes-3l45) -- [Submission Template](https://dev.to/new/midnightchallenge) - ---- -最終更新: 2025-08-24 \ No newline at end of file diff --git a/private_test/ai_agent_workflow.md b/private_test/ai_agent_workflow.md deleted file mode 100644 index 160531a4..00000000 --- a/private_test/ai_agent_workflow.md +++ /dev/null @@ -1,113 +0,0 @@ -# AI Agents Challenge - ワークフロー設計 - -## 基本的な流れ - -### 1. **Nyash側** - トリガー送信 -```nyash -box PriceMonitorAgent { - init { webhookUrl, products } - - checkPrices() { - local net = new NetBox() - local data = new MapBox() - data.set("action", "check_prices") - data.set("products", me.products) - - // n8nのWebhookをトリガー - net.post(me.webhookUrl, data.toJsonBox()) - } -} -``` - -### 2. **n8n側** - ワークフロー -``` -[Webhook] → [AI Agent] → [Bright Data] → [Process] → [Response] -``` - -- **Webhook Node**: Nyashからのリクエストを受信 -- **AI Agent Node**: - - どのサイトをスクレイピングするか決定 - - Bright Dataへのクエリを構築 -- **Bright Data Node**: - - 実際のWebスクレイピング実行 - - 商品価格などのデータ取得 -- **Process**: データ整形・比較 -- **Response**: 結果をWebhookで返す - -### 3. **具体例: 価格監視エージェント** - -#### Nyash側の実装 -```nyash -static box Main { - main() { - local agent = new PriceMonitorAgent() - agent.webhookUrl = "https://your-n8n-instance.n8n.cloud/webhook/price-monitor" - - // 監視したい商品 - local products = new ArrayBox() - products.push({ - "name": "iPhone 15", - "url": "https://example.com/iphone15", - "targetPrice": 800 - }) - - agent.products = products - agent.checkPrices() - } -} -``` - -#### n8nでの設定手順 - -1. **Webhook Node設定** - - Method: POST - - Path: /price-monitor - - Response Mode: Last Node - -2. **AI Agent Node設定** - - Model: GPT-3.5/4 - - Prompt: - ``` - 商品リストから、Bright Dataでスクレイピングすべき - URLとセレクタを生成してください。 - 商品: {{$json.products}} - ``` - -3. **Bright Data Node設定** - - Scraper API使用 - - Dynamic URL from AI Agent - - Extract: 価格情報 - -4. **Code Node(価格比較)** - ```javascript - const currentPrice = $node["Bright Data"].json.price; - const targetPrice = $node["Webhook"].json.products[0].targetPrice; - - if (currentPrice < targetPrice) { - return { - alert: true, - message: `価格が下がりました!${currentPrice}円` - }; - } - ``` - -### チャレンジの要件チェック -- ✅ n8n AI Agent Node使用 -- ✅ Bright Data Verified Node使用 -- ✅ 実用的で複雑 -- ✅ 創造的(Nyash言語使用) - -### デモ動画に含めるべき内容 -1. Nyashコードの実行 -2. n8nワークフローの動作 -3. Bright Dataでのデータ取得 -4. 結果の表示 - -### 簡単に始めるには - -まず超シンプルな例から: -1. Webhookを受け取る -2. AI Agentに「今日の天気は?」と聞く -3. 結果を返す - -これが動いたら、Bright Dataを追加していく! \ No newline at end of file diff --git a/private_test/alternative_agent_ideas.md b/private_test/alternative_agent_ideas.md deleted file mode 100644 index d35ff44c..00000000 --- a/private_test/alternative_agent_ideas.md +++ /dev/null @@ -1,67 +0,0 @@ -# Bright Dataアクセス不可の場合の代替案 - -## 🌟 アイデア1: 公開APIを使ったAIエージェント - -Bright Dataの代わりに公開APIを使う: - -```nyash -box WeatherAIAgent { - init { n8nWebhook, apiKeys } - - // OpenWeatherMap APIなど無料APIを使用 - getWeatherInsights(location) { - local net = new NetBox() - - // n8n経由でAI分析 - local data = new MapBox() - data.set("location", location) - data.set("action", "analyze_weather") - - return net.post(me.n8nWebhook, data.toJsonBox()) - } -} -``` - -## 🌟 アイデア2: GitHub/GitLab API活用 - -```nyash -box CodeReviewAgent { - // GitHubのPRを自動レビュー - reviewPullRequest(repoUrl, prNumber) { - // GitHub APIでPR情報取得 - // n8n AI AgentでコードレビューSS - // 結果をコメントとして投稿 - } -} -``` - -## 🌟 アイデア3: RSS/ニュースAPI - -```nyash -box NewsDigestAgent { - // NewsAPI.orgなどの無料ニュースAPI使用 - // AI要約・分析を提供 -} -``` - -## n8nワークフロー構成 - -1. **Webhook** → **HTTP Request (API)** → **AI Agent** → **Response** - -Bright Data Nodeの代わりに: -- HTTP Request Node(一般的なAPI呼び出し) -- RSS Read Node(RSS/Atomフィード) -- GitHub Node(GitHub API) -- その他の統合 - -## 審査基準への対応 - -- ✅ AI Agent Node使用(必須) -- ✅ 実用的で複雑 -- ✅ 創造的(Nyash使用) -- ⚠️ Bright Data未使用(減点の可能性) - -## 結論 - -Bright Dataが使えなくても、他のデータソースでAIエージェントは作れる! -ただし、賞金狙いなら要件を満たす必要があるので、メールで相談するのがベスト。 \ No newline at end of file diff --git a/private_test/test_n8n_webhook.nyash b/private_test/test_n8n_webhook.nyash deleted file mode 100644 index 7b3b0d1d..00000000 --- a/private_test/test_n8n_webhook.nyash +++ /dev/null @@ -1,22 +0,0 @@ -// n8n Webhook連携テスト -static box Main { - main() { - // NetBoxプラグインでHTTPリクエスト - local net = new NetBox() - - // n8nのWebhook URLに送信(例) - local webhookUrl = "https://webhook.n8n.io/test" - local data = new MapBox() - data.set("message", "Hello from Nyash!") - data.set("timestamp", new TimeBox().now()) - - print("Sending webhook to n8n...") - local response = net.post(webhookUrl, data.toJsonBox()) - - if response.isOk() { - print("Success! Response: " + response.getValue()) - } else { - print("Error: " + response.getError()) - } - } -} \ No newline at end of file diff --git a/private_test/zkp_tutorial_demo.nyash b/private_test/zkp_tutorial_demo.nyash deleted file mode 100644 index a159aca6..00000000 --- a/private_test/zkp_tutorial_demo.nyash +++ /dev/null @@ -1,71 +0,0 @@ -// Midnight Network ZKPチュートリアル - Nyashデモ -// ゼロ知識証明を視覚的に理解する - -static box Main { - main() { - local tutorial = new ZKPTutorial() - tutorial.start() - } -} - -box ZKPTutorial { - init { console } - - constructor() { - me.console = new ConsoleBox() - } - - start() { - me.console.log("🔐 ゼロ知識証明チュートリアル by Nyash") - me.console.log("=====================================") - - // レッスン1: 年齢証明 - me.ageProofDemo() - - // レッスン2: 秘密投票 - me.votingDemo() - - // レッスン3: 残高証明 - me.balanceProofDemo() - } - - ageProofDemo() { - me.console.log("\n📝 レッスン1: 年齢証明") - me.console.log("実際の年齢を明かさずに「18歳以上」を証明します") - - local alice = new Person("Alice", 25) - local proof = alice.proveAgeAbove(18) - - me.console.log("Aliceの証明: " + proof) - me.console.log("検証結果: 18歳以上 ✅") - me.console.log("実際の年齢: 秘密のまま 🤫") - } - - votingDemo() { - me.console.log("\n🗳️ レッスン2: 秘密投票") - // 投票内容を秘密にしながら有効性を証明 - } - - balanceProofDemo() { - me.console.log("\n💰 レッスン3: 残高証明") - // 具体的な金額を明かさずに「十分な残高がある」を証明 - } -} - -box Person { - init { name, age } - - constructor(name, age) { - me.name = name - me.age = age - } - - proveAgeAbove(minAge) { - // 実際のMidnightではZKP生成 - // デモ用の簡易実装 - if me.age >= minAge { - return "VALID_PROOF_" + new RandomBox().randomString(16) - } - return "INVALID_PROOF" - } -} \ No newline at end of file diff --git a/src/backend/vm.rs b/src/backend/vm.rs index bf698e0e..7a44b6cb 100644 --- a/src/backend/vm.rs +++ b/src/backend/vm.rs @@ -539,10 +539,41 @@ impl VM { } /// Call a method on a Box - simplified version of interpreter method dispatch - pub(super) fn call_box_method(&self, box_value: Box, method: &str, _args: Vec>) -> Result, VMError> { + pub(super) fn call_box_method(&self, box_value: Box, method: &str, mut _args: Vec>) -> Result, VMError> { // For now, implement basic methods for common box types // This is a simplified version - real implementation would need full method dispatch + // 🌟 Universal methods pre-dispatch (non-invasive) + match method { + "toString" => { + if !_args.is_empty() { + return Ok(Box::new(StringBox::new(format!("Error: toString() expects 0 arguments, got {}", _args.len())))); + } + return Ok(Box::new(StringBox::new(box_value.to_string_box().value))); + } + "type" => { + if !_args.is_empty() { + return Ok(Box::new(StringBox::new(format!("Error: type() expects 0 arguments, got {}", _args.len())))); + } + return Ok(Box::new(StringBox::new(box_value.type_name()))); + } + "equals" => { + if _args.len() != 1 { + return Ok(Box::new(StringBox::new(format!("Error: equals() expects 1 argument, got {}", _args.len())))); + } + let rhs = _args.remove(0); + let eq = box_value.equals(&*rhs); + return Ok(Box::new(eq)); + } + "clone" => { + if !_args.is_empty() { + return Ok(Box::new(StringBox::new(format!("Error: clone() expects 0 arguments, got {}", _args.len())))); + } + return Ok(box_value.clone_box()); + } + _ => {} + } + // ResultBox (NyashResultBox - new) if let Some(result_box) = box_value.as_any().downcast_ref::() { match method { @@ -562,11 +593,6 @@ impl VM { // Legacy box_trait::ResultBox is no longer handled here (migration complete) - // Generic fallback: toString for any Box type - if method == "toString" { - return Ok(Box::new(StringBox::new(box_value.to_string_box().value))); - } - // StringBox methods if let Some(string_box) = box_value.as_any().downcast_ref::() { match method { diff --git a/src/box_factory/builtin.rs b/src/box_factory/builtin.rs index cdad31ff..2fa8d56d 100644 --- a/src/box_factory/builtin.rs +++ b/src/box_factory/builtin.rs @@ -455,8 +455,15 @@ impl BuiltinBoxFactory { }); } let name = args[0].to_string_box().value; + // Accept multiple payload forms: JSON string, JSONBox, MapBox + let payload_str = if let Some(jb) = args[1].as_any().downcast_ref::() { + jb.to_string() + } else if let Some(mb) = args[1].as_any().downcast_ref::() { + mb.toJSON().to_string_box().value + } else { + args[1].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), diff --git a/src/boxes/p2p_box.rs b/src/boxes/p2p_box.rs index 9c83b703..cc3168b9 100644 --- a/src/boxes/p2p_box.rs +++ b/src/boxes/p2p_box.rs @@ -179,9 +179,15 @@ impl P2PBox { if let Some(method_box) = handler.as_any().downcast_ref::() { let method_clone = method_box.clone(); let intent_name = intent_str.to_string(); + // capture state holders for receive-side tracing + let last_from = Arc::clone(&self.last_from); + let last_intent = Arc::clone(&self.last_intent_name); t.register_intent_handler(&intent_name, Box::new(move |env| { // flagがtrueのときのみ実行 if flag.load(Ordering::SeqCst) { + // Update receive-side traces for E2E visibility + if let Ok(mut lf) = last_from.write() { *lf = Some(env.from.clone()); } + if let Ok(mut li) = last_intent.write() { *li = Some(env.intent.get_name().to_string_box().value); } let _ = method_clone.invoke(vec![ Box::new(env.intent.clone()), Box::new(StringBox::new(env.from.clone())), @@ -253,6 +259,16 @@ impl P2PBox { } } + /// デバッグ: intentに対する有効ハンドラー数(trueフラグ数) + pub fn debug_active_handler_count(&self, intent_name: Box) -> Box { + let name = intent_name.to_string_box().value; + let flags = self.handler_flags.read().unwrap(); + let cnt = flags.get(&name) + .map(|v| v.iter().filter(|f| f.load(Ordering::SeqCst)).count()) + .unwrap_or(0); + Box::new(crate::box_trait::IntegerBox::new(cnt as i64)) + } + /// 最後に受信したfromを取得(ループバック検証用) pub fn get_last_from(&self) -> Box { let v = self.last_from.read().unwrap().clone().unwrap_or_default(); @@ -354,4 +370,83 @@ mod tests { assert_eq!(p.get_last_from().to_string_box().value, "alice".to_string()); assert_eq!(p.get_last_intent_name().to_string_box().value, "ping".to_string()); } + + /// Internal helper for tests: register raw Rust handler with optional async reply + impl P2PBox { + #[allow(dead_code)] + fn __debug_on_rust(&self, intent: &str, reply_intent: Option<&str>) { + if let Ok(mut t) = self.transport.write() { + let intent_name = intent.to_string(); + let last_from = Arc::clone(&self.last_from); + let last_intent = Arc::clone(&self.last_intent_name); + // create self clone for reply + let self_clone = self.clone(); + let reply_name = reply_intent.map(|s| s.to_string()); + t.register_intent_handler(&intent_name, Box::new(move |env| { + if let Ok(mut lf) = last_from.write() { *lf = Some(env.from.clone()); } + if let Ok(mut li) = last_intent.write() { *li = Some(env.intent.get_name().to_string_box().value); } + if let Some(rn) = reply_name.clone() { + let to = env.from.clone(); + std::thread::spawn(move || { + // slight delay to avoid lock contention + std::thread::sleep(std::time::Duration::from_millis(5)); + let intent = IntentBox::new(rn, serde_json::json!({})); + let _ = self_clone.send(Box::new(StringBox::new(to)), Box::new(intent)); + }); + } + })); + } + } + } + + #[test] + fn two_node_ping_pong() { + let alice = P2PBox::new("alice".to_string(), TransportKind::InProcess); + let bob = P2PBox::new("bob".to_string(), TransportKind::InProcess); + // bob replies pong to ping + bob.__debug_on_rust("ping", Some("pong")); + // alice listens pong + alice.__debug_on_rust("pong", None); + // send ping + let ping = IntentBox::new("ping".to_string(), serde_json::json!({})); + let _ = alice.send(Box::new(StringBox::new("bob")), Box::new(ping)); + // bob should record ping + assert_eq!(bob.get_last_intent_name().to_string_box().value, "ping"); + // allow async reply + std::thread::sleep(std::time::Duration::from_millis(20)); + // alice should record pong + assert_eq!(alice.get_last_intent_name().to_string_box().value, "pong"); + } + + #[test] + fn on_once_disables_after_first_delivery() { + let p = P2PBox::new("alice".to_string(), TransportKind::InProcess); + // Register one-time handler for 'hello' + let handler = crate::method_box::MethodBox::new(Box::new(p.clone()), "noop".to_string()); + let _ = p.on_once(Box::new(StringBox::new("hello")), Box::new(handler)); + // Initially active = 1 + let c0 = p.debug_active_handler_count(Box::new(StringBox::new("hello"))); + assert_eq!(c0.to_string_box().value, "1"); + // Send twice to self + let intent = IntentBox::new("hello".to_string(), serde_json::json!({})); + let _ = p.send(Box::new(StringBox::new("alice")), Box::new(intent.clone())); + let _ = p.send(Box::new(StringBox::new("alice")), Box::new(intent)); + // After first delivery, once-flag should be false => active count = 0 + let c1 = p.debug_active_handler_count(Box::new(StringBox::new("hello"))); + assert_eq!(c1.to_string_box().value, "0"); + } + + #[test] + fn off_clears_handlers() { + let p = P2PBox::new("bob".to_string(), TransportKind::InProcess); + let handler = crate::method_box::MethodBox::new(Box::new(p.clone()), "noop".to_string()); + let _ = p.on(Box::new(StringBox::new("bye")), Box::new(handler)); + // Active = 1 + let c0 = p.debug_active_handler_count(Box::new(StringBox::new("bye"))); + assert_eq!(c0.to_string_box().value, "1"); + // Off + let _ = p.off(Box::new(StringBox::new("bye"))); + let c1 = p.debug_active_handler_count(Box::new(StringBox::new("bye"))); + assert_eq!(c1.to_string_box().value, "0"); + } } diff --git a/src/interpreter/expressions/calls.rs b/src/interpreter/expressions/calls.rs index 9d93c90d..236123f2 100644 --- a/src/interpreter/expressions/calls.rs +++ b/src/interpreter/expressions/calls.rs @@ -229,6 +229,38 @@ impl NyashInterpreter { // オブジェクトを評価(通常のメソッド呼び出し) let obj_value = self.execute_expression(object)?; idebug!("🔍 DEBUG: execute_method_call - object type: {}, method: {}", obj_value.type_name(), method); + + // 🌟 ユニバーサルメソッド前段ディスパッチ(非侵襲) + // toString()/type()/equals(x)/clone() をトレイトに直結 + match method { + "toString" => { + if !arguments.is_empty() { + return Err(RuntimeError::InvalidOperation { message: format!("toString() expects 0 arguments, got {}", arguments.len()) }); + } + return Ok(Box::new(obj_value.to_string_box())); + } + "type" => { + if !arguments.is_empty() { + return Err(RuntimeError::InvalidOperation { message: format!("type() expects 0 arguments, got {}", arguments.len()) }); + } + return Ok(Box::new(StringBox::new(obj_value.type_name()))); + } + "equals" => { + if arguments.len() != 1 { + return Err(RuntimeError::InvalidOperation { message: format!("equals() expects 1 argument, got {}", arguments.len()) }); + } + let rhs = self.execute_expression(&arguments[0])?; + let eq = obj_value.equals(&*rhs); + return Ok(Box::new(eq)); + } + "clone" => { + if !arguments.is_empty() { + return Err(RuntimeError::InvalidOperation { message: format!("clone() expects 0 arguments, got {}", arguments.len()) }); + } + return Ok(obj_value.clone_box()); + } + _ => {} + } // Builtin dispatch (centralized) if let Some(res) = self.dispatch_builtin_method(&obj_value, method, arguments) { diff --git a/src/interpreter/methods/p2p_methods.rs b/src/interpreter/methods/p2p_methods.rs index cc0bd39f..3e39d9f0 100644 --- a/src/interpreter/methods/p2p_methods.rs +++ b/src/interpreter/methods/p2p_methods.rs @@ -47,6 +47,9 @@ impl NyashInterpreter { method: &str, arguments: &[ASTNode], ) -> Result, RuntimeError> { + if crate::interpreter::utils::debug_on() || std::env::var("NYASH_DEBUG_P2P").unwrap_or_default() == "1" { + eprintln!("[Interp:P2P] {}(..) called with {} args", method, arguments.len()); + } match method { // ノードID取得 "getNodeId" | "getId" => Ok(p2p_box.get_node_id()), @@ -74,7 +77,7 @@ impl NyashInterpreter { } // on メソッド実装(ResultBox返却) - , "on" => { + "on" => { if arguments.len() < 2 { return Err(RuntimeError::InvalidOperation { message: "on requires (intentName, handler) arguments".to_string() }); } diff --git a/src/messaging/message_bus.rs b/src/messaging/message_bus.rs index a5ca4406..de35ff20 100644 --- a/src/messaging/message_bus.rs +++ b/src/messaging/message_bus.rs @@ -114,6 +114,9 @@ impl MessageBusData { /// メッセージをルーティング pub fn route(&self, to: &str, intent: IntentBox, from: &str) -> Result<(), SendError> { if let Some(endpoint) = self.nodes.get(to) { + if std::env::var("NYASH_DEBUG_P2P").unwrap_or_default() == "1" { + eprintln!("[MessageBus] route {} -> {} intent={}", from, to, intent.get_name().to_string_box().value); + } endpoint.deliver(intent, from); Ok(()) } else { diff --git a/src/transport/inprocess.rs b/src/transport/inprocess.rs index 143ddb24..4e3713b7 100644 --- a/src/transport/inprocess.rs +++ b/src/transport/inprocess.rs @@ -109,6 +109,9 @@ impl Transport for InProcessTransport { let cb = std::sync::Arc::new(cb); let cb_clone = cb.clone(); // Adapt to MessageBus handler signature + if std::env::var("NYASH_DEBUG_P2P").unwrap_or_default() == "1" { + eprintln!("[InProcessTransport] register handler node={} intent={}", self.node_id, intent_name); + } self.add_handler(&intent_name, Box::new(move |intent_box: IntentBox, from: &str| { let env = IntentEnvelope { from: from.to_string(), @@ -133,7 +136,17 @@ impl Transport for InProcessTransport { impl Drop for InProcessTransport { fn drop(&mut self) { - // NOTE: Temporarily disabled unregister to avoid interfering with shared-node lifetimes. - // Proper refcounted unregister will be implemented later. + // Safe unregister: only remove if the current endpoint matches the registry entry + if let Ok(mut bus) = self.bus.lock() { + let removed = bus.unregister_if_same(&self.node_id, &self.endpoint); + if std::env::var("NYASH_DEBUG_P2P").unwrap_or_default() == "1" { + eprintln!( + "[InProcessTransport::drop] node_id={} removed={} (bus={:?})", + self.node_id, + removed, + &*bus + ); + } + } } } diff --git a/test-nyash.toml b/test-nyash.toml deleted file mode 100644 index 9f4c9437..00000000 --- a/test-nyash.toml +++ /dev/null @@ -1,29 +0,0 @@ -# Test Configuration for plugin-tester -# Valid TOML structure - -# Plugin name mappings (simple version) -[plugin_names] -FileBox = "nyash-filebox-plugin" - -# Plugin configurations with method type information -[plugins.FileBox] -plugin_name = "nyash-filebox-plugin" - -[plugins.FileBox.methods] -# readは引数なし -read = { args = [] } - -# writeは文字列をbytesとして送る -write = { args = [{ from = "string", to = "bytes" }] } - -# openは2つの文字列引数 -open = { args = [ - { name = "path", from = "string", to = "string" }, - { name = "mode", from = "string", to = "string" } -] } - -# closeは引数なし、戻り値なし -close = { args = [] } - -# existsは引数なし、戻り値はbool(将来拡張) -exists = { args = [], returns = "bool" } \ No newline at end of file diff --git a/test.wat.wat b/test.wat.wat deleted file mode 100644 index 097eb142..00000000 --- a/test.wat.wat +++ /dev/null @@ -1,241 +0,0 @@ -(module - (import "env" "print" (func $print (param i32) )) - (import "env" "print_str" (func $print_str (param i32 i32) )) - (import "env" "console_log" (func $console_log (param i32 i32) )) - (import "env" "canvas_fillRect" (func $canvas_fillRect (param i32 i32 i32 i32 i32 i32 i32 i32) )) - (import "env" "canvas_fillText" (func $canvas_fillText (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) )) - (import "env" "box_to_string" (func $box_to_string (param i32) (result i32))) - (import "env" "box_print" (func $box_print (param i32) )) - (import "env" "box_equals" (func $box_equals (param i32 i32) (result i32))) - (import "env" "box_clone" (func $box_clone (param i32) (result i32))) - (memory (export "memory") 1) - (data (i32.const 4096) "\48\65\6c\6c\6f\20\66\72\6f\6d\20\57\41\53\4d\21") - (data (i32.const 4112) "\54\68\65\20\61\6e\73\77\65\72\20\69\73\3a\20") - (global $heap_ptr (mut i32) (i32.const 2048)) - (func $malloc (param $size i32) (result i32) - (local $ptr i32) - (local $aligned_size i32) - - ;; Align size to 4-byte boundary - local.get $size - i32.const 3 - i32.add - i32.const -4 - i32.and - local.set $aligned_size - - ;; Get current heap pointer - global.get $heap_ptr - local.set $ptr - - ;; Advance heap pointer by aligned size - global.get $heap_ptr - local.get $aligned_size - i32.add - global.set $heap_ptr - - ;; Return allocated pointer - local.get $ptr - ) - (func $box_alloc (param $type_id i32) (param $field_count i32) (result i32) - (local $ptr i32) - (local $total_size i32) - - ;; Calculate total size: header (12) + fields (field_count * 4) - local.get $field_count - i32.const 4 - i32.mul - i32.const 12 - i32.add - local.set $total_size - - ;; Allocate memory - local.get $total_size - call $malloc - local.set $ptr - - ;; Initialize type_id - local.get $ptr - local.get $type_id - i32.store - - ;; Initialize ref_count to 1 - local.get $ptr - i32.const 4 - i32.add - i32.const 1 - i32.store - - ;; Initialize field_count - local.get $ptr - i32.const 8 - i32.add - local.get $field_count - i32.store - - ;; Return box pointer - local.get $ptr - ) - (func $alloc_stringbox (result i32) - (local $ptr i32) - - ;; Allocate memory for box - i32.const 20 - call $malloc - local.set $ptr - - ;; Initialize type_id - local.get $ptr - i32.const 4097 - i32.store - - ;; Initialize ref_count to 1 - local.get $ptr - i32.const 4 - i32.add - i32.const 1 - i32.store - - ;; Initialize field_count - local.get $ptr - i32.const 8 - i32.add - i32.const 2 - i32.store - - ;; Return box pointer - local.get $ptr - ) - (func $alloc_integerbox (result i32) - (local $ptr i32) - - ;; Allocate memory for box - i32.const 16 - call $malloc - local.set $ptr - - ;; Initialize type_id - local.get $ptr - i32.const 4098 - i32.store - - ;; Initialize ref_count to 1 - local.get $ptr - i32.const 4 - i32.add - i32.const 1 - i32.store - - ;; Initialize field_count - local.get $ptr - i32.const 8 - i32.add - i32.const 1 - i32.store - - ;; Return box pointer - local.get $ptr - ) - (func $alloc_boolbox (result i32) - (local $ptr i32) - - ;; Allocate memory for box - i32.const 16 - call $malloc - local.set $ptr - - ;; Initialize type_id - local.get $ptr - i32.const 4099 - i32.store - - ;; Initialize ref_count to 1 - local.get $ptr - i32.const 4 - i32.add - i32.const 1 - i32.store - - ;; Initialize field_count - local.get $ptr - i32.const 8 - i32.add - i32.const 1 - i32.store - - ;; Return box pointer - local.get $ptr - ) - (func $alloc_databox (result i32) - (local $ptr i32) - - ;; Allocate memory for box - i32.const 16 - call $malloc - local.set $ptr - - ;; Initialize type_id - local.get $ptr - i32.const 4101 - i32.store - - ;; Initialize ref_count to 1 - local.get $ptr - i32.const 4 - i32.add - i32.const 1 - i32.store - - ;; Initialize field_count - local.get $ptr - i32.const 8 - i32.add - i32.const 1 - i32.store - - ;; Return box pointer - local.get $ptr - ) - (func $main (local $0 i32) (local $1 i32) (local $2 i32) (local $3 i32) (local $4 i32) - nop - call $alloc_stringbox - local.set $0 - local.get $0 - i32.const 12 - i32.add - i32.const 4096 - i32.store - local.get $0 - i32.const 16 - i32.add - i32.const 16 - i32.store - local.get $0 - call $print - i32.const 0 - local.set $1 - i32.const 42 - local.set $2 - call $alloc_stringbox - local.set $3 - local.get $3 - i32.const 12 - i32.add - i32.const 4112 - i32.store - local.get $3 - i32.const 16 - i32.add - i32.const 15 - i32.store - local.get $3 - local.get $2 - i32.add - local.set $4 - local.get $4 - call $print - local.get $4 - return - ) - (export "main" (func $main)) -) diff --git a/test_nyash_v2.toml b/test_nyash_v2.toml deleted file mode 100644 index 2bfa6389..00000000 --- a/test_nyash_v2.toml +++ /dev/null @@ -1,24 +0,0 @@ -# Nyash v2 configuration test file - -# Legacy single-box plugins (for backward compatibility) -[plugins] -FileBox = "plugins/nyash-filebox-plugin/target/release/libnyash_filebox_plugin.so" - -# New multi-box plugin libraries -[plugins.libraries] -"nyash-test-multibox" = { plugin_path = "plugins/nyash-test-multibox/target/release/libnyash_test_multibox.so", provides = ["TestBoxA", "TestBoxB"] } - -# Box type definitions -[plugins.types.TestBoxA] -library = "nyash-test-multibox" -type_id = 200 - -[plugins.types.TestBoxA.methods] -hello = { args = [] } - -[plugins.types.TestBoxB] -library = "nyash-test-multibox" -type_id = 201 - -[plugins.types.TestBoxB.methods] -greet = { args = [] } \ No newline at end of file