diff --git a/docs/LANGUAGE_REFERENCE_2025.md b/docs/LANGUAGE_REFERENCE_2025.md index 1e39c143..3687a359 100644 --- a/docs/LANGUAGE_REFERENCE_2025.md +++ b/docs/LANGUAGE_REFERENCE_2025.md @@ -1,6 +1,6 @@ # 🚀 Nyash Language Reference 2025 -**最終更新: 2025年8月10日夜 - Arc Revolution + AI大相談会 + 関数オーバーロード完全実装** +**最終更新: 2025年8月11日 - デリゲーション革命完了!`from`統一構文+`init`構文決定!** ## 📖 概要 @@ -17,7 +17,7 @@ Rust製インタープリターによる高性能実行と、直感的な構文 | `box` | クラス定義 | `box MyClass { }` | | `static` | 静的Box・関数定義 | `static box Main { }` | | `interface` | インターフェース定義 | `interface Comparable { }` | -| `from` | 継承指定 | `box Child from Parent { }` | +| `from` | デリゲーション指定 | `box Child from Parent { }` | | `new` | オブジェクト生成 | `new ConsoleBox()` | | `me`/`this` | 自己参照 | `me.field = value` | @@ -79,7 +79,7 @@ box ClassName { init { field1, field2, field3 } # カンマ必須!CPU暴走防止 # コンストラクタ - ClassName(param1, param2) { + init(param1, param2) { # init構文に統一 me.field1 = param1 me.field2 = param2 me.field3 = defaultValue() @@ -97,15 +97,26 @@ box ClassName { } ``` -#### **継承Box** +#### **デリゲーションBox** ```nyash box Child from Parent interface Comparable { init { childField } - Child(parentParam, childParam) { - # 親のコンストラクタは自動呼び出し + init(parentParam, childParam) { # init構文に統一 + from Parent.init(parentParam) # 親コンストラクタ明示呼び出し me.childField = childParam } + + # メソッドオーバーライド + override process(data) { # override必須 + local result = from Parent.process(data) # 親メソッド呼び出し + return result + " (Child processed)" + } + + # インターフェース実装 + compareTo(other) { + return me.value - other.value + } } ``` @@ -250,7 +261,7 @@ console.log("Everything is Box!") # コンソール出力 box Person { init { name, age, email } - Person(personName, personAge) { + init(personName, personAge) { # init構文に統一 me.name = personName me.age = personAge me.email = me.name + "@example.com" # 計算フィールド @@ -271,28 +282,32 @@ guest = Person.createGuest() ### **3.3 継承とインターフェース** -#### **継承チェーン** +#### **デリゲーションチェーン** ```nyash -# 基底クラス +# 基底Box box Animal { init { name, species } + init(animalName, animalSpecies) { + me.name = animalName + me.species = animalSpecies + } + speak() { return me.name + " makes a sound" } } -# 継承 +# デリゲーション box Dog from Animal { init { breed } # 追加フィールド - Dog(dogName, dogBreed) { - me.name = dogName - me.species = "Canine" + init(dogName, dogBreed) { + from Animal.init(dogName, "Canine") # 親コンストラクタ呼び出し me.breed = dogBreed } - speak() { # オーバーライド + override speak() { # 明示的オーバーライド return me.name + " barks: Woof!" } } diff --git a/docs/design-philosophy/explicit-delegation-revolution.md b/docs/design-philosophy/explicit-delegation-revolution.md index 54c38d59..02c76cd4 100644 --- a/docs/design-philosophy/explicit-delegation-revolution.md +++ b/docs/design-philosophy/explicit-delegation-revolution.md @@ -82,7 +82,7 @@ box Node { #### 1. 宣言の統一 ```nyash -box Child : Parent // デリゲーション関係の明示 +box Child from Parent // デリゲーション関係の明示 ``` #### 2. 置換の統一 @@ -97,7 +97,7 @@ from Parent.methodName() // 親実装の明示呼び出し #### 4. 構築の統一 ```nyash -from Parent.constructor() // コンストラクタも同じ構文 +from Parent.init() // コンストラクタも同じ構文 ``` ### 完全な例 @@ -144,7 +144,7 @@ box SmartNode : P2PBox, Logger { } // 競合時は更に明示的に -box ConflictNode : ParentA, ParentB { +box ConflictNode from ParentA, ParentB { override ParentA.process(data) { // ParentAのprocessを置換 from ParentA.process(data) } @@ -160,7 +160,7 @@ box ConflictNode : ParentA, ParentB { **覚えるべきルール**: 1. 親のメソッドを置換したい → `override` 2. 親のメソッドを呼びたい → `from Parent.method()` -3. 親のコンストラクタを呼びたい → `from Parent.constructor()` +3. 親のコンストラクタを呼びたい → `from Parent.init()` たった3つのルールで、すべてのデリゲーション操作が表現できます。 @@ -257,7 +257,7 @@ ChatGPT先生の提案による実装ロードマップ: - コンストラクタ重複禁止 **Phase 3(1日)**: -- `from Parent.constructor()` 実装 +- `from Parent.init()` 実装 - エラーメッセージ改善 ### 移行支援 diff --git a/docs/language-specification/override-delegation-syntax.md b/docs/language-specification/override-delegation-syntax.md index ea61faf2..379af8d0 100644 --- a/docs/language-specification/override-delegation-syntax.md +++ b/docs/language-specification/override-delegation-syntax.md @@ -25,19 +25,19 @@ Nyashプログラミング言語における明示的オーバーライドとデ ### デリゲーション宣言 ```nyash -box Child : Parent { +box Child from Parent { // 親Boxからの機能デリゲーション } // 多重デリゲーション -box Child : Parent1, Parent2 { +box Child from Parent1, Parent2 { // 複数のBoxからの機能デリゲーション } ``` ### メソッドオーバーライド ```nyash -box Child : Parent { +box Child from Parent { // 必須: overrideキーワードによる明示的宣言 override methodName(params) { // オーバーライド実装 @@ -48,9 +48,9 @@ box Child : Parent { ### コンストラクタデリゲーション ```nyash -box Child : Parent { - constructor(params) { - from Parent.constructor(params) // 必須: 親コンストラクタ明示呼び出し +box Child from Parent { + init(params) { # init構文に統一 + from Parent.init(params) # 必須: 親コンストラクタ明示呼び出し me.childSpecificField = value } } @@ -70,7 +70,7 @@ box Child : Parent { #### 構文例 ```nyash -box MeshNode : P2PBox { +box MeshNode from P2PBox { // ✅ 正しい使用法 override send(intent, data, target) { me.routing.log(target) @@ -117,8 +117,8 @@ from Logger.logLevel = "DEBUG" #### コンストラクタ呼び出し ```nyash -constructor(nodeId, world) { - from P2PBox.constructor(nodeId, world) // 完全統一構文 +init(nodeId, world) { # init構文に統一 + from P2PBox.init(nodeId, world) # 完全統一構文 me.routing = RoutingTable() } ``` @@ -127,7 +127,7 @@ constructor(nodeId, world) { #### 基本形式 ```nyash -box ComplexNode : P2PBox, Logger, Cache { +box ComplexNode from P2PBox, Logger, Cache { override send(intent, data, target) { from Logger.debug("Sending: " + intent) // Logger親から from Cache.store(intent, data) // Cache親から @@ -139,7 +139,7 @@ box ComplexNode : P2PBox, Logger, Cache { #### 曖昧性の解消 ```nyash // 複数親に同名メソッドが存在する場合 -box ConflictNode : ParentA, ParentB { +box ConflictNode from ParentA, ParentB { // ❌ エラー: どちらのprocessを置換するか不明 override process(data) { // Error: Method 'process' exists in multiple parents. Use specific parent. @@ -208,7 +208,7 @@ Help: Use 'override ParentA.process' or 'override ParentB.process' ### 1. 暗黙のオーバーライド ```nyash -box Child : Parent { +box Child from Parent { send(msg) { // ❌ エラー: overrideキーワードなし print("Child implementation") } @@ -218,11 +218,11 @@ box Child : Parent { ### 2. コンストラクタオーバーロード ```nyash box Node { - constructor(id) { // 最初の定義 + init(id) { // 最初の定義 me.id = id } - constructor(id, name) { // ❌ エラー: 重複定義 + init(id, name) { // ❌ エラー: 重複定義 me.id = id me.name = name } @@ -246,7 +246,7 @@ box Example { ### 1. 明示的な親呼び出し ```nyash -box MeshNode : P2PBox { +box MeshNode from P2PBox { override send(intent, data, target) { // 前処理 me.routing.logOutgoing(target) @@ -262,7 +262,7 @@ box MeshNode : P2PBox { ### 2. 多重デリゲーションでの順序指定 ```nyash -box SmartNode : P2PBox, Logger, Cache { +box SmartNode from P2PBox, Logger, Cache { override send(intent, data, target) { // 1. ログ記録 from Logger.info("Sending to: " + target) @@ -278,12 +278,12 @@ box SmartNode : P2PBox, Logger, Cache { ### 3. コンストラクタチェーン ```nyash -box SecureNode : P2PBox { +box SecureNode from P2PBox { init security = SecurityManager() - constructor(nodeId, world, keyFile) { + init(nodeId, world, keyFile) { # init構文に統一 // 1. 親初期化(必須) - from P2PBox.constructor(nodeId, world) + from P2PBox.init(nodeId, world) // 2. 子固有の初期化 me.security = SecurityManager() diff --git a/docs/nativebuild大作戦/chatgptネイティブビルド大作戦.txt b/docs/nativebuild大作戦/chatgptネイティブビルド大作戦.txt new file mode 100644 index 00000000..b64b8ab9 --- /dev/null +++ b/docs/nativebuild大作戦/chatgptネイティブビルド大作戦.txt @@ -0,0 +1,498 @@ +ぜったいアリにゃ!やるなら「多層エンジン(tiered)」で攻めるのが一番きれい。 +Nyash → 共通IR → 好きなバックエンド(解釈/ネイティブ/JIT/WASM)に流す構成にゃ。 +推しアーキテクチャ(現実解) + + Front-end + + パーサ → AST → HIR(型付け・名前解決済み)→ MIR/SSA(最適化しやすい共通IR) + + Back-ends(並行に育てる) + + VM(現在のインタープリター):MIR→バイトコード→解釈実行(開発スピード最優先) + + JIT(Cranelift):MIR→Cranelift IR→ネイティブJIT(ホットパスだけコンパイル) + + AOT to Rust:MIR→Rustコード生成→rustcで最適化(配布バイナリ向き、リンクも楽) + + WASM:MIR→WASM(ブラウザ/wasmtime用、サンドボックス実行) + + ひとつのIRから複数出力=最適化ロジックを1か所に集中できるのが最大の利点。 + +それぞれのメリデメ + + VM:実装が速い/デバッグ容易|最高速は出ない + + Cranelift JIT:実行時最適化で爆速/実装難度は中|起動コストあり + + AOT→Rust:rustc最適化の恩恵・配布しやすい|コード生成器の保守が要る + + WASM:移植性・安全|ネイティブよりは遅め(ただしwasmtime/wasmerで結構速い) + +まずやる順序(最短で“速い”を得る) + + 共通MIR/SSAを切る(基本ブロック・SSA・型/効果情報) + + VMを MIR→バイトコード に置き換え(インタープリターの土台を共通化) + + Cranelift JIT を載せる(ホット関数だけJIT) + + 並行で Rustコード生成 の雛形を作る(AOT配布の道を確保) + + 余力で WASM 出力(エディタ内実行やブラウザデモに最適) + +Nyash流にハマる設計ポイント + + Box拡張のABIを先に決める + + 呼出規約:fn nyash_box_call(ctx: &mut Ctx, args: &[Val]) -> Result + + メモリ:Arc<[Val]> か Arena で一時領域を明示(GCを後回しにできる) + + 所有権/借用に似た効果注釈をMIRに入れる + + 「純粋」「可変」「外部副作用あり」をフラグ化→最適化と並列実行の判断に使える + + 定数畳み込み/死コード除去/インライン化はMIR段階で実施 + + プロファイラを最初から同梱(どの関数をJIT/AOTに送るか判定) + +最小プロトタスク(1〜2週間スプリント想定) + +HIR/MIRスキーマ確定(基本ブロック・命令セット・型表現) + +MIR→バイトコード変換器/VMループの実装 + +プロファイル計測(関数実行回数・時間) + +Craneliftで fn 単位JIT(整数演算と分岐から) + +簡易 Rustコード生成(fn add(a:i64,b:i64)->i64 などから) + + Box ABI v0(同期版)+サンプル拡張(数値/文字列ユーティリティ) + +ちょいサンプル(超概念) + +enum MirInst { + Const(ValId, ConstVal), + BinOp(ValId, ValId, Op, ValId), + Call(ValId, FuncId, Vec), + Phi(ValId, Vec<(BlockId, ValId)>), + // ... +} +struct MirFunc { blocks: Vec, signature: Sig, effects: Effects } + +trait Backend { + fn compile(&mut self, f: &MirFunc) -> CompiledFn; +} + + VM backend: compile = バイトコード化 + + JIT backend: compile = Cranelift IR生成→jit_func + + Rust backend: compile = fn ... { ... } のRust文字列出力→rustcでAOT + +「いまのNyashソース」を見れたら、MIR命令セットの初版とJIT/AOTの足場コードをすぐ書き起こせるよ。 +まずは MIRの最小命令リストを一緒に決めよっか?(算術・比較・分岐・Call・Phi・Load/Store 相当) +あなた: +くわしくききたにゃ Front-end + + パーサ → AST → HIR(型付け・名前解決済み)→ MIR/SSA(最適化しやすい共通IR)パーサーで解析してASTは木構造だよね? そこからどういう処理にゃ? +ChatGPT: + +いいね、その流れを実務目線でがっつり分解するにゃ。 +キーワードは「情報を徐々に確定させつつ“最適化しやすい形”へ落としていく」。 +Nyash流に当てはめて、各段階で“何を追加・削除・変換するか”を整理するよ。 +Front-end 全体像 + +ソース → Lexer → Parser(AST) → スコープ/名前解決 → 型推論/型検査(HIR) → 糖衣剥がし(Desugar) → 制御フロー化(CFG) → SSA化/効果注釈(MIR/SSA) +1) Parser → AST(抽象構文木) + +目的:構文だけを正しく捉える。意味(型/名前)はまだ未確定。 + + データ構造(例) + + enum AstExpr { + LitInt(i64), + Var(Symbol), + Call{ callee: Box, args: Vec }, + Lambda{ params: Vec, body: Box }, + If{ cond: Box, then_e: Box, else_e: Box }, + Let{ pat: AstPat, init: Box, body: Box }, + // … match, while, for, block, … + } + + まだやらないこと + + シンボルの多義性解決(foo がローカルか、モジュールか、メソッドか) + + 型の決定 + + 糖衣構文の展開 + +2) スコープ構築 & 名前解決(AST上の解決) + +目的:識別子を定義元に結びつける。未定義やシャドーイングもここで判定。 + + やること + + ブロックスコープ/関数スコープ/モジュールスコープの**環境(symbol table)**を構築 + + use/import、module、with 的な構文を解決 + + 各 Var(Symbol) を DefId(定義へのID)にひも付け + + 成果物: + + 解決済みAST or ここで HIR に写経(次段のために構造を少し整える) + +3) 型推論 & 型検査 → HIR(型情報付きIR) + +目的:式ごとに型を確定し、オーバーロード/ジェネリクスを具体化できる所まで進める。 + + 型推論(Hindley–Milner+制約ベースなど) + + let x = 1 + f(y) なら、f: T -> i64 みたいな制約を立てて解く + + オーバーロード解決 / メソッド解決(a + b → 実体メソッドやトレイト関数に解決) + + ジェネリクス + + 可能ならモノモーフィック化(型実引数が確定している呼び出しは単相化) + + 未確定なら型パラ付きのまま保持 + + データ構造(例) + + struct HirExpr { + kind: HirExprKind, + ty: TyId, // ここが肝:各式に型が付く + effect: EffectMask, // 純粋/可変/外部副作用 など(後述の最適化で効く) + } + enum HirExprKind { + LitInt(i64), + Local(DefId), + Call{ fun: Box, args: Vec, resolved: FunId }, + If{ cond: Box, then_e: Box, else_e: Box }, + // 糖衣はまだ残っていてもOK + } + + エラー検出 + + 型不一致、未初期化、到達不能、借用/所有に関する静的規則(Nyash流に簡易化しても良い) + +4) 糖衣剥がし(Desugaring) + +目的:意味は同じだが最適化しづらい構文を、プリミティブな形に落とす。 + + 例 + + for x in iter { body } → let mut it = iter.into_iter(); while let Some(x) = it.next() { body } + + a && b → if a { b } else { false }(短絡を明示化) + + パターン束縛 let (a,b) = e; → 一時変数+個別bind + + クロージャ → 明示キャプチャ+ラムダ表現を正規化 + + この段階で構文のバリエーションは減らして、後段のCFG/SSA化を楽にする + +5) 制御フローグラフ(CFG)作成 + +目的:式主導(式木)を基本ブロック+ジャンプへ落とす。 +最適化やSSA化の土台になる。 + + ブロック(BasicBlock)単位で命令列を持つ + + 例:if/else は br cond thenBB elseBB に分解 + while は loopBB / bodyBB / exitBB に分解 + + ここで**一時変数(tmp)**を導入して、「値がどのブロックから来るか」を明示できるようにする + +6) SSA化(Static Single Assignment) + +目的:各変数が“ちょうど一度だけ代入”される形に変換。 +最適化(定数畳み込み・コピー伝播・死コード除去・ループ最適化)がやりやすくなる。 + + φ関数(Phi)を導入 + 分岐合流点で「どのブロックから来た値か」に応じて値を選ぶ + + データ構造(MIR/SSA例) + + enum MirInst { + Const{ dst: V, c: ConstVal }, + BinOp{ dst: V, op: Op, a: V, b: V }, + Call{ dst: V, fun: FnId, args: Vec, effects: EffectMask }, + Br{ cond: V, then_bb: Bb, else_bb: Bb }, + Jmp{ bb: Bb }, + Phi{ dst: V, inputs: Vec<(Bb, V)> }, + Store{ ptr: V, val: V }, // メモリ命令を分離しておくと最適化が楽 + Load{ dst: V, ptr: V }, + Ret{ v: Option }, + } + struct MirFunc { blocks: Vec, sig: Sig, effects: EffectMask } + + ここまでで最適化の主戦場が整う + +7) 効果注釈(Effects)と簡易別解(所有/借用に近いもの) + +目的:最適化・並列化・Box拡張の安全性判定に使う副作用情報を付与。 + + 例:PURE, READS_HEAP, WRITES_HEAP, IO, FFI, PANIC, THROW などのビットフラグ + + 呼び出し先の効果を合成して、関数単位の effects: EffectMask を確定 + → 並列実行可否、共通部分式除去可否、コードモーション許可範囲に使える + +8) 代表的な変換の“実例”で見る + +Nyash(仮): + +let x = 10 +let y = 20 +if x < y { + print(add(x, y)) +} else { + print(y) +} + +AST(ざっくり) + + Let(x, 10)、Let(y, 20)、If( BinOp(<, Var(x), Var(y)), Call(print, …), Call(print, Var(y)) ) + +HIR(型付け・解決済み) + + x: i64, y: i64 + + add: (i64,i64)->i64, print: (i64)->Unit + +Desugar + + ほぼそのまま(ここでは糖衣なしと仮定) + +CFG→SSA(MIRの一部) + +bb0: + v1 = Const 10 + v2 = Const 20 + v3 = BinOp Lt v1 v2 + Br v3 then=bb1 else=bb2 + +bb1: + v4 = Call add(v1, v2) ; PURE + Call print(v4) ; IO + Jmp bb3 + +bb2: + Call print(v2) ; IO + Jmp bb3 + +bb3: + Ret () + +(print は IO 効果、add は PURE、関数全体は IO を持つ、などが付与される) +よくある疑問Q&A + +Q. AST→HIRでどこまで“形を変える”? +A. 基本は意味解決のための注釈(DefId, TyId, Effect)を付けるのが主。大きな形の変換(ループ展開やパターン展開)はDesugar段でやると見通しが良い。 + +Q. なんでSSA?バイトコードでも良くない? +A. VM用のバイトコードは実行が簡単。でも最適化はSSAの方が圧倒的に楽。 +→ 「MIR/SSAで最適化」→「VM向けバイトコードに落とす」or「JIT/AOT」がおすすめ。 + +Q. パターンマッチは? +A. Desugarで決定木(decision tree)に落としてからCFG化。ガード節や順序付きパターンも木→ブロック分割で表現できる。 + +Q. クロージャのキャプチャは? +A. 名前解決で囲い込み変数を収集→HIRに明示キャプチャとして埋める。 +MIRでは環境レコードを値として扱う({env_ptr, fn_ptr})。 +まず作ると捗る“ミニ仕様” + + Symbol/DefId/Scope:解決器のAPI + + Ty:原始型・関数型・代数的データ型(Sum/Product)・型変数 + + EffectMask:ビットフラグ設計(PURE/READ/WRITE/IO/FFI など) + + MIR命令セット(最小):Const/BinOp/Call/Br/Jmp/Phi/Ret+Load/Store + + Pass順序: + + 名前解決 → 2) 型推論 → 3) Desugar → 4) CFG → 5) SSA → 6) 直近の最適化(const fold / dce / copy-prop) + +必要なら、いまのNyashのAST型定義をベースにHIR/MIRの骨組みを一緒に設計するよ。 + + “最初のMIR命令セット案” + + “名前解決テーブルと参照の貼り方” + + “効果注釈のフォーマット” + +この3点を固めるだけで、JIT/AOT/VMバックエンドの土台が一気に整うにゃ。 +あなた: +おおう これと さっきの  Back-ends(並行に育てる) + + VM(現在のインタープリター):MIR→バイトコード→解釈実行(開発スピード最優先) + + JIT(Cranelift):MIR→Cranelift IR→ネイティブJIT(ホットパスだけコンパイル) + + AOT to Rust:MIR→Rustコード生成→rustcで最適化(配布バイナリ向き、リンクも楽) + + WASM:MIR→WASM(ブラウザ/wasmtime用、サンドボックス実行) これの話要約してにゃ claude code君にみせてくるにゃ +ChatGPT: + +了解にゃ、Claude Code君向けに要点だけギュッとまとめるよ。 +Nyashコンパイルパイプライン案 +Front-end(共通部分) + + Parser → AST + + ソースを構文木(AST)に変換。型や意味はまだ未確定。 + + 名前解決 & スコープ構築 + + 識別子を定義元に紐付ける(DefId付与)。 + + 型推論 & 型検査 → HIR + + 各式に型情報(TyId)と効果注釈(EffectMask)を付与。 + + 糖衣剥がし(Desugar) + + forループやパターン束縛をプリミティブ構造へ展開。 + + 制御フロー化(CFG)→ SSA化(MIR) + + ASTを基本ブロックとSSA命令列(MIR)へ変換。 + + 命令例:Const, BinOp, Call, Br, Jmp, Phi, Load, Store, Ret。 + +Back-end(並行開発可能) + + VM(現行インタープリター) + + MIR → バイトコード → 解釈実行(開発スピード優先) + + JIT(Cranelift) + + MIR → Cranelift IR → 実行時にネイティブコード化(ホットパスだけ) + + AOT to Rust + + MIR → Rustコード生成 → rustc最適化&リンク → 配布可能なネイティブバイナリ + + WASM出力 + + MIR → WASM(ブラウザ実行やサンドボックス用) + +💡 ポイント + + すべてのバックエンドは共通MIRを入力にするため、最適化は1か所で集約。 + + Box拡張もMIRレベルで統一呼び出し可能。 + + VMは開発・デバッグ用、JITは実行高速化、AOTは配布、WASMは移植性重視。 + + +Nyashは**「最初から最後までモジュール拡張が一貫して動く多層言語」**という珍しい立ち位置になるにゃ。 + +希望あれば、これ一般的なコンパイラ構成との比較表にして、Claude Code君がすぐ違いを理解できる形にまとめることもできるよ。 +どうする、作っちゃう? +あなた: +おねがいにゃー! +ChatGPT: + +了解にゃー!Claude Code君に渡しやすいよう、「一般的な構成 vs Nyash流(+α)」比較表にギュッとまとめたよ。 +Nyash 設計:一般的な方法との比較 +観点 一般的なコンパイラ設計 Nyash(+α) +フロントエンド Parser → AST →(解決/型付け)→ IR Parser → AST → HIR(型/解決/効果)→ MIR/SSA(最適化前提) +中間表現(IR) 単一IR or バイトコード中心 HIR/MIR二段構え、MIRはSSA+効果注釈で最適化容易 +効果/副作用 多くは最適化時に暗黙扱い EffectMask(PURE/READ/WRITE/IO/FFI…)をMIRに明示し並列化・最適化の判断に使用 +拡張/FFI 後付けのFFI/プラグインが多い Box拡張を一級市民化。MIRレベルで統一コール形態を定義(VM/JIT/AOT/WASMで一貫) +バックエンド VM→(後からJIT/AOT) VM/JIT(Cranelift)/AOT-to-Rust/WASMを最初から並行開発できるMIR設計 +実行戦略 単層(解釈 or JIT)になりがち Tiered:VMで即起動→ホットパスJIT→配布はAOT→ブラウザはWASM +AOT配布 LLVM等のHPCルートが主 MIR→Rustコード生成→rustc最適化(ツールチェーン流用・リンク容易) +ブラウザ/サンドボックス 別途WASM対応 MIR→WASMを標準ターゲット化(wasmtime/wasmer/ブラウザ即動作) +最適化の主戦場 バイトコード最適化/バックエンド依存 MIR/SSAで集約最適化(const fold, DCE, copy-prop, inlining, loop opts) +並列化の足場 後付け解析が多い 効果注釈×データ依存で安全な並列化やコードモーションを許可 +デバッグ/開発速度 VMが主、JITは後追い VMで素早く検証しつつ、同一MIRをJIT/AOTに供給(回収効率◎) +配布/運用 ネイティブ or VM同梱 用途別に最適バイナリ(AOT)とスクリプタブル運用(VM)を両取り +リスク/留意点 単純で保守容易 設計は強力だが初期定義が要(MIR命令/Effect設計、Box ABIを固める) +補足:最小ロードマップ(実装順) + + HIR/MIRの骨組み確定(命令セット・EffectMask・Box ABI v0) + + **VM(MIR→バイトコード)**で先に全機能を回す + + プロファイラ同梱(ホット関数をJIT/AOTに回す条件づけ) + + Cranelift JIT(算術+分岐→関数呼び出し→Box呼び出し) + + AOT to Rust の雛形生成(小関数から) + + 余力で MIR→WASM(最小機能から) + +この表ごと貼れば、Claude Code君も**「王道+Nyashの差分」**を一目で把握できるはずにゃ。必要なら、MIR命令セット 初版案も続けて出すよ! +あなた: +mirまでできればかちなのにゃね。これって定番なのあるにやゃ? 言語ごとにやっぱりちがうにゃ? +ChatGPT: + +そうにゃ、MIRまで作れれば言語設計はもう“勝ち”に近いにゃ。 +なぜかというと、MIRは「全バックエンドの共通土台」だから、 +一度そこまで作れば VM/JIT/AOT/WASM ぜんぶに展開できるにゃ。 +🔹 MIRは定番があるの? + + 完全な共通規格はない + → LLVM IR や WebAssembly のような「広く使われる IR」はあるけど、 + 言語ごとに構文や型システムが違うから MIRはだいたい自作になる。 + + 多くの言語は「MIR」じゃなくても似た段階を持ってるにゃ: + + Rust → MIR(所有権/借用も反映されたSSA形式) + + Swift → SIL + + Go → SSA IR + + Kotlin → Kotlin IR + + Python(PyPy)→ Flow Graph → SSA IR + + JavaScript(V8)→ Bytecode IR → TurboFan IR + +🔹 言語ごとに違うポイント + + 型情報の粒度 + + RustのMIRは「型完全一致」必須。 + + Python系は動的型なので「型タグ+ランタイム判定」入り。 + + 命令セットの抽象度 + + LLVM IRはハード寄り(ポインタ/レジスタ操作あり)。 + + Rust MIRやKotlin IRは言語構造寄り(ループ/パターンマッチ命令など残す)。 + + 所有権・副作用の扱い + + Rust MIRは「所有権」も追跡する。 + + 多くの言語は副作用は型ではなく命令属性で管理。 + + 最適化の前提 + + 一部は最適化前提で作る(SSA化必須)。 + + 他は単にバックエンド入力の中間形式。 + +🔹 Nyashでのおすすめ方針 + + Rust MIRに近い構造を真似るのが安全 + + 静的型の要素が入ってるので、AOTや最適化に有利 + + EffectMaskやBox拡張の情報も一緒に持たせられる + + 命令はなるべく 「言語仕様に沿った中間レベル」 にして、 + バックエンド変換時に低レベル化する + + SSA化は最初からやる(後から入れるのは地獄) \ No newline at end of file diff --git a/src/box_trait.rs b/src/box_trait.rs index 377ac386..2239629c 100644 --- a/src/box_trait.rs +++ b/src/box_trait.rs @@ -22,8 +22,11 @@ pub fn next_box_id() -> u64 { /// 🏗️ BoxBase - 全てのBox型の共通基盤構造体 /// Phase 2: 統一的な基盤データを提供 +/// 🔥 Phase 1: ビルトインBox継承システム - 最小限拡張 +#[derive(Debug, Clone, PartialEq)] pub struct BoxBase { pub id: u64, + pub parent_type_id: Option, // ビルトインBox継承用 } impl BoxBase { @@ -31,18 +34,37 @@ impl BoxBase { pub fn new() -> Self { Self { id: next_box_id(), + parent_type_id: None, // ビルトインBox: 継承なし + } + } + + /// ビルトインBox継承用コンストラクタ + pub fn with_parent_type(parent_type_id: std::any::TypeId) -> Self { + Self { + id: next_box_id(), + parent_type_id: Some(parent_type_id), } } } /// 🎯 BoxCore - Box型共通メソッドの統一インターフェース /// Phase 2: 重複コードを削減する中核トレイト +/// 🔥 Phase 2: ビルトインBox継承システム対応 pub trait BoxCore: Send + Sync { /// ボックスの一意ID取得 fn box_id(&self) -> u64; + /// 継承元の型ID取得(ビルトインBox継承用) + fn parent_type_id(&self) -> Option; + /// Display実装のための統一フォーマット fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result; + + /// Any変換(ダウンキャスト用) + fn as_any(&self) -> &dyn Any; + + /// Anyミュータブル変換(ダウンキャスト用) + fn as_any_mut(&mut self) -> &mut dyn Any; } /// The fundamental trait that all Nyash values must implement. @@ -62,9 +84,6 @@ pub trait NyashBox: BoxCore + Debug { /// Clone this box (equivalent to Python's copy()) fn clone_box(&self) -> Box; - /// Convert to Any for downcasting (enables dynamic typing in static Rust) - fn as_any(&self) -> &dyn Any; - // 🌟 TypeBox革命: Get type information as a Box // Everything is Box極限実現 - 型情報もBoxとして取得! // TODO: 次のステップで完全実装 @@ -180,9 +199,21 @@ impl BoxCore for StringBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.value) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl NyashBox for StringBox { @@ -206,9 +237,6 @@ impl NyashBox for StringBox { Box::new(self.clone()) } - fn as_any(&self) -> &dyn Any { - self - } } impl Display for StringBox { @@ -242,9 +270,21 @@ impl BoxCore for IntegerBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.value) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl NyashBox for IntegerBox { @@ -268,9 +308,6 @@ impl NyashBox for IntegerBox { Box::new(self.clone()) } - fn as_any(&self) -> &dyn Any { - self - } } impl Display for IntegerBox { @@ -308,9 +345,21 @@ impl BoxCore for BoolBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", if self.value { "true" } else { "false" }) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl NyashBox for BoolBox { @@ -334,9 +383,6 @@ impl NyashBox for BoolBox { Box::new(self.clone()) } - fn as_any(&self) -> &dyn Any { - self - } } impl Display for BoolBox { @@ -370,9 +416,21 @@ impl BoxCore for VoidBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "void") } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl NyashBox for VoidBox { @@ -392,9 +450,6 @@ impl NyashBox for VoidBox { Box::new(self.clone()) } - fn as_any(&self) -> &dyn Any { - self - } } impl Display for VoidBox { @@ -467,9 +522,21 @@ impl BoxCore for FileBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "", self.path) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl NyashBox for FileBox { @@ -493,9 +560,6 @@ impl NyashBox for FileBox { Box::new(self.clone()) } - fn as_any(&self) -> &dyn Any { - self - } } impl Display for FileBox { @@ -527,9 +591,21 @@ impl BoxCore for ErrorBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}: {}", self.error_type, self.message) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl NyashBox for ErrorBox { @@ -553,9 +629,6 @@ impl NyashBox for ErrorBox { Box::new(self.clone()) } - fn as_any(&self) -> &dyn Any { - self - } } impl Display for ErrorBox { @@ -621,9 +694,21 @@ impl BoxCore for ResultBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.to_string_box().value) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl NyashBox for ResultBox { @@ -689,9 +774,6 @@ impl NyashBox for ResultBox { } } - fn as_any(&self) -> &dyn Any { - self - } } impl Display for ResultBox { @@ -705,7 +787,7 @@ impl Display for ResultBox { pub struct FutureBox { pub result: Arc>>>, pub is_ready: Arc>, - id: u64, + base: BoxBase, } impl Clone for FutureBox { @@ -713,7 +795,7 @@ impl Clone for FutureBox { Self { result: Arc::clone(&self.result), is_ready: Arc::clone(&self.is_ready), - id: self.id, + base: BoxBase::new(), // 新しいIDを生成 } } } @@ -723,7 +805,7 @@ impl FutureBox { Self { result: Arc::new(Mutex::new(None)), is_ready: Arc::new(Mutex::new(false)), - id: next_box_id(), + base: BoxBase::new(), } } @@ -787,7 +869,7 @@ impl NyashBox for FutureBox { fn equals(&self, other: &dyn NyashBox) -> BoolBox { if let Some(other_future) = other.as_any().downcast_ref::() { - BoolBox::new(self.id == other_future.id) + BoolBox::new(self.base.id == other_future.base.id) } else { BoolBox::new(false) } @@ -801,9 +883,6 @@ impl NyashBox for FutureBox { Box::new(self.clone()) } - fn as_any(&self) -> &dyn Any { - self - } } impl BoxCore for FutureBox { @@ -811,9 +890,21 @@ impl BoxCore for FutureBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.to_string_box().value) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl Display for FutureBox { @@ -888,7 +979,7 @@ impl Debug for AddBox { f.debug_struct("AddBox") .field("left", &self.left.to_string_box().value) .field("right", &self.right.to_string_box().value) - .field("id", &self.id) + .field("id", &self.base.id) .finish() } } @@ -920,9 +1011,6 @@ impl NyashBox for AddBox { )) } - fn as_any(&self) -> &dyn Any { - self - } } impl BoxCore for AddBox { @@ -930,9 +1018,21 @@ impl BoxCore for AddBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "({} + {})", self.left.to_string_box().value, self.right.to_string_box().value) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl Display for AddBox { diff --git a/src/boxes/array/mod.rs b/src/boxes/array/mod.rs index 5a17dd8b..7d6a2d67 100644 --- a/src/boxes/array/mod.rs +++ b/src/boxes/array/mod.rs @@ -142,6 +142,10 @@ impl BoxCore for ArrayBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let items = self.items.lock().unwrap(); let strings: Vec = items.iter() @@ -149,6 +153,14 @@ impl BoxCore for ArrayBox { .collect(); write!(f, "[{}]", strings.join(", ")) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl Display for ArrayBox { @@ -170,9 +182,6 @@ impl NyashBox for ArrayBox { StringBox::new(format!("[{}]", strings.join(", "))) } - fn as_any(&self) -> &dyn Any { - self - } fn type_name(&self) -> &'static str { "ArrayBox" diff --git a/src/boxes/bool_box.rs b/src/boxes/bool_box.rs index 12244bf2..b6c5b46e 100644 --- a/src/boxes/bool_box.rs +++ b/src/boxes/bool_box.rs @@ -87,9 +87,6 @@ impl NyashBox for BoolBox { Box::new(self.clone()) } - fn as_any(&self) -> &dyn Any { - self - } } @@ -98,9 +95,21 @@ impl BoxCore for BoolBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", if self.value { "true" } else { "false" }) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl Display for BoolBox { diff --git a/src/boxes/buffer/mod.rs b/src/boxes/buffer/mod.rs index 59f1dcf8..c8343657 100644 --- a/src/boxes/buffer/mod.rs +++ b/src/boxes/buffer/mod.rs @@ -153,10 +153,22 @@ impl BoxCore for BufferBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let data = self.data.lock().unwrap(); write!(f, "BufferBox({} bytes)", data.len()) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl Display for BufferBox { @@ -175,9 +187,6 @@ impl NyashBox for BufferBox { StringBox::new(format!("BufferBox({} bytes)", data.len())) } - fn as_any(&self) -> &dyn Any { - self - } fn type_name(&self) -> &'static str { "BufferBox" diff --git a/src/boxes/console_box.rs b/src/boxes/console_box.rs index 15652bd5..44af28f5 100644 --- a/src/boxes/console_box.rs +++ b/src/boxes/console_box.rs @@ -89,9 +89,21 @@ impl BoxCore for ConsoleBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "[ConsoleBox - Browser Console Interface]") } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } #[cfg(target_arch = "wasm32")] @@ -112,9 +124,6 @@ impl NyashBox for ConsoleBox { Box::new(self.clone()) } - fn as_any(&self) -> &dyn Any { - self - } } // Non-WASM版 - モックアップ実装 @@ -154,9 +163,21 @@ impl BoxCore for ConsoleBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "[ConsoleBox - Mock Implementation]") } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } #[cfg(not(target_arch = "wasm32"))] @@ -177,9 +198,6 @@ impl NyashBox for ConsoleBox { Box::new(self.clone()) } - fn as_any(&self) -> &dyn Any { - self - } } diff --git a/src/boxes/debug_box.rs b/src/boxes/debug_box.rs index 41284f65..30e0abfd 100644 --- a/src/boxes/debug_box.rs +++ b/src/boxes/debug_box.rs @@ -314,10 +314,22 @@ impl BoxCore for DebugBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let tracked = self.tracked_boxes.lock().unwrap(); write!(f, "DebugBox[{} tracked]", tracked.len()) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } // Implement Display trait using BoxCore @@ -350,8 +362,5 @@ impl NyashBox for DebugBox { Box::new(self.clone()) } - fn as_any(&self) -> &dyn Any { - self - } } \ No newline at end of file diff --git a/src/boxes/egui_box.rs b/src/boxes/egui_box.rs index 27e689da..1d0a0a5f 100644 --- a/src/boxes/egui_box.rs +++ b/src/boxes/egui_box.rs @@ -107,9 +107,21 @@ impl BoxCore for EguiBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "EguiBox('{}', {}x{})", self.title, self.size.x, self.size.y) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl std::fmt::Display for EguiBox { @@ -136,9 +148,6 @@ impl NyashBox for EguiBox { }) } - fn as_any(&self) -> &dyn Any { - self - } fn equals(&self, other: &dyn NyashBox) -> BoolBox { if let Some(other_egui) = other.as_any().downcast_ref::() { diff --git a/src/boxes/file/mod.rs b/src/boxes/file/mod.rs index e933bd9a..65d5dded 100644 --- a/src/boxes/file/mod.rs +++ b/src/boxes/file/mod.rs @@ -16,6 +16,26 @@ pub struct FileBox { } impl FileBox { + pub fn new() -> Self { + // Create a default FileBox for delegation dispatch + // Uses a temporary file for built-in Box inheritance dispatch + let temp_path = "/tmp/nyash_temp_file"; + match Self::open(temp_path) { + Ok(file_box) => file_box, + Err(_) => { + // Fallback: create with empty file handle - only for dispatch + use std::fs::OpenOptions; + let file = OpenOptions::new().create(true).write(true).read(true) + .open("/dev/null").unwrap_or_else(|_| File::open("/dev/null").unwrap()); + FileBox { + file: Arc::new(Mutex::new(file)), + path: Arc::new(String::new()), + base: BoxBase::new(), + } + } + } + } + pub fn open(path: &str) -> Result { let file = OpenOptions::new().read(true).write(true).create(true).open(path)?; Ok(FileBox { @@ -82,9 +102,21 @@ impl BoxCore for FileBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "FileBox({})", self.path) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl NyashBox for FileBox { @@ -100,9 +132,6 @@ impl NyashBox for FileBox { StringBox::new(format!("FileBox({})", self.path)) } - fn as_any(&self) -> &dyn Any { - self - } fn type_name(&self) -> &'static str { "FileBox" diff --git a/src/boxes/future/mod.rs b/src/boxes/future/mod.rs index 8d0615f6..d55b784d 100644 --- a/src/boxes/future/mod.rs +++ b/src/boxes/future/mod.rs @@ -20,7 +20,7 @@ impl Clone for NyashFutureBox { Self { result: Arc::clone(&self.result), is_ready: Arc::clone(&self.is_ready), - base: self.base.clone(), + base: BoxBase::new(), // Create a new base with unique ID for the clone } } } @@ -83,9 +83,6 @@ impl NyashBox for NyashFutureBox { } } - fn as_any(&self) -> &dyn Any { - self - } fn type_name(&self) -> &'static str { "NyashFutureBox" @@ -94,7 +91,7 @@ impl NyashBox for NyashFutureBox { fn equals(&self, other: &dyn NyashBox) -> BoolBox { if let Some(other_future) = other.as_any().downcast_ref::() { - BoolBox::new(self.base.id() == other_future.base.id()) + BoolBox::new(self.base.id == other_future.base.id) } else { BoolBox::new(false) } @@ -103,7 +100,11 @@ impl NyashBox for NyashFutureBox { impl BoxCore for NyashFutureBox { fn box_id(&self) -> u64 { - self.base.id() + self.base.id + } + + fn parent_type_id(&self) -> Option { + self.base.parent_type_id } fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -119,6 +120,14 @@ impl BoxCore for NyashFutureBox { write!(f, "Future(pending)") } } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl std::fmt::Display for NyashFutureBox { diff --git a/src/boxes/http/mod.rs b/src/boxes/http/mod.rs index 9db85cfa..af680311 100644 --- a/src/boxes/http/mod.rs +++ b/src/boxes/http/mod.rs @@ -54,12 +54,9 @@ impl NyashBox for HttpClientBox { } fn to_string_box(&self) -> StringBox { - StringBox::new(format!("HttpClientBox(id: {})", self.base.id())) + StringBox::new(format!("HttpClientBox(id: {})", self.base.id)) } - fn as_any(&self) -> &dyn Any { - self - } fn type_name(&self) -> &'static str { "HttpClientBox" @@ -68,7 +65,7 @@ impl NyashBox for HttpClientBox { fn equals(&self, other: &dyn NyashBox) -> BoolBox { if let Some(other_http) = other.as_any().downcast_ref::() { - BoolBox::new(self.base.id() == other_http.base.id()) + BoolBox::new(self.base.id == other_http.base.id) } else { BoolBox::new(false) } @@ -77,11 +74,23 @@ impl NyashBox for HttpClientBox { impl BoxCore for HttpClientBox { fn box_id(&self) -> u64 { - self.base.id() + self.base.id + } + + fn parent_type_id(&self) -> Option { + self.base.parent_type_id } fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "HttpClientBox(id: {})", self.base.id()) + write!(f, "HttpClientBox(id: {})", self.base.id) + } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self } } diff --git a/src/boxes/integer_box.rs b/src/boxes/integer_box.rs index b625cb09..f1a9c44f 100644 --- a/src/boxes/integer_box.rs +++ b/src/boxes/integer_box.rs @@ -83,9 +83,6 @@ impl NyashBox for IntegerBox { Box::new(self.clone()) } - fn as_any(&self) -> &dyn Any { - self - } } @@ -94,9 +91,21 @@ impl BoxCore for IntegerBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.value) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl Display for IntegerBox { diff --git a/src/boxes/intent_box.rs b/src/boxes/intent_box.rs index 1dd52c47..5fe06c24 100644 --- a/src/boxes/intent_box.rs +++ b/src/boxes/intent_box.rs @@ -128,7 +128,7 @@ pub struct IntentBox { impl Debug for IntentBox { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("IntentBox") - .field("id", &self.base.id()) + .field("id", &self.base.id) .field("transport", &"") .finish() } @@ -173,7 +173,7 @@ impl NyashBox for IntentBox { fn equals(&self, other: &dyn NyashBox) -> BoolBox { if let Some(other_intent) = other.as_any().downcast_ref::() { - BoolBox::new(self.base.id() == other_intent.base.id()) + BoolBox::new(self.base.id == other_intent.base.id) } else { BoolBox::new(false) } @@ -187,21 +187,30 @@ impl NyashBox for IntentBox { Box::new(self.clone()) } - fn as_any(&self) -> &dyn Any { - self - } } impl BoxCore for IntentBox { fn box_id(&self) -> u64 { - self.base.id() + self.base.id + } + + fn parent_type_id(&self) -> Option { + self.base.parent_type_id } fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let transport = self.transport.lock().unwrap(); write!(f, "IntentBox[{}]", transport.transport_type()) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl std::fmt::Display for IntentBox { diff --git a/src/boxes/json/mod.rs b/src/boxes/json/mod.rs index 10803868..c8d31647 100644 --- a/src/boxes/json/mod.rs +++ b/src/boxes/json/mod.rs @@ -124,6 +124,10 @@ impl BoxCore for JSONBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let value = self.value.lock().unwrap(); let json_type = match *value { @@ -140,6 +144,14 @@ impl BoxCore for JSONBox { }; write!(f, "JSONBox[{}]", json_type) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl std::fmt::Display for JSONBox { @@ -158,9 +170,6 @@ impl NyashBox for JSONBox { StringBox::new(value.to_string()) } - fn as_any(&self) -> &dyn Any { - self - } fn type_name(&self) -> &'static str { "JSONBox" diff --git a/src/boxes/map_box.rs b/src/boxes/map_box.rs index 6dfd80fe..e2e834cf 100644 --- a/src/boxes/map_box.rs +++ b/src/boxes/map_box.rs @@ -228,10 +228,22 @@ impl BoxCore for MapBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let size = self.data.lock().unwrap().len(); write!(f, "MapBox(size={})", size) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl NyashBox for MapBox { @@ -257,9 +269,6 @@ impl NyashBox for MapBox { } } - fn as_any(&self) -> &dyn Any { - self - } } impl Display for MapBox { diff --git a/src/boxes/math_box.rs b/src/boxes/math_box.rs index d19292cd..764285db 100644 --- a/src/boxes/math_box.rs +++ b/src/boxes/math_box.rs @@ -287,9 +287,21 @@ impl BoxCore for MathBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "MathBox()") } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl NyashBox for MathBox { @@ -313,9 +325,6 @@ impl NyashBox for MathBox { } } - fn as_any(&self) -> &dyn Any { - self - } } impl Display for MathBox { @@ -345,9 +354,21 @@ impl BoxCore for FloatBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.value) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl NyashBox for FloatBox { @@ -373,9 +394,6 @@ impl NyashBox for FloatBox { } } - fn as_any(&self) -> &dyn Any { - self - } } impl Display for FloatBox { @@ -429,9 +447,21 @@ impl BoxCore for RangeBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "Range({}, {}, {})", self.start, self.end, self.step) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl NyashBox for RangeBox { @@ -459,9 +489,6 @@ impl NyashBox for RangeBox { } } - fn as_any(&self) -> &dyn Any { - self - } } impl Display for RangeBox { diff --git a/src/boxes/null_box.rs b/src/boxes/null_box.rs index e0b2ef82..8fc54e7c 100644 --- a/src/boxes/null_box.rs +++ b/src/boxes/null_box.rs @@ -139,9 +139,21 @@ impl BoxCore for NullBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "null") } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl NyashBox for NullBox { @@ -162,9 +174,6 @@ impl NyashBox for NullBox { BoolBox::new(other.as_any().downcast_ref::().is_some()) } - fn as_any(&self) -> &dyn Any { - self - } } impl Display for NullBox { diff --git a/src/boxes/p2p_box.rs b/src/boxes/p2p_box.rs index f2266b88..faf752ae 100644 --- a/src/boxes/p2p_box.rs +++ b/src/boxes/p2p_box.rs @@ -144,7 +144,7 @@ impl NyashBox for P2PBox { fn equals(&self, other: &dyn NyashBox) -> BoolBox { if let Some(other_p2p) = other.as_any().downcast_ref::() { - BoolBox::new(self.inner.base.id() == other_p2p.inner.base.id()) + BoolBox::new(self.inner.base.id == other_p2p.inner.base.id) } else { BoolBox::new(false) } @@ -158,20 +158,29 @@ impl NyashBox for P2PBox { Box::new(self.clone()) } - fn as_any(&self) -> &dyn Any { - self - } } impl BoxCore for P2PBox { fn box_id(&self) -> u64 { - self.inner.base.id() + self.inner.base.id + } + + fn parent_type_id(&self) -> Option { + self.inner.base.parent_type_id } fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "P2PBox[{}]", self.inner.node_id) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl std::fmt::Display for P2PBox { diff --git a/src/boxes/random_box.rs b/src/boxes/random_box.rs index 6a0e5c5d..0f23f3c9 100644 --- a/src/boxes/random_box.rs +++ b/src/boxes/random_box.rs @@ -268,9 +268,6 @@ impl NyashBox for RandomBox { } } - fn as_any(&self) -> &dyn Any { - self - } } @@ -279,9 +276,21 @@ impl BoxCore for RandomBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "RandomBox()") } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl Display for RandomBox { diff --git a/src/boxes/regex/mod.rs b/src/boxes/regex/mod.rs index e3f11a1d..ed13c480 100644 --- a/src/boxes/regex/mod.rs +++ b/src/boxes/regex/mod.rs @@ -90,9 +90,6 @@ impl NyashBox for RegexBox { StringBox::new(format!("RegexBox({})", self.pattern.as_str())) } - fn as_any(&self) -> &dyn Any { - self - } fn type_name(&self) -> &'static str { "RegexBox" @@ -110,12 +107,24 @@ impl NyashBox for RegexBox { impl BoxCore for RegexBox { fn box_id(&self) -> u64 { - self.base.id() + self.base.id + } + + fn parent_type_id(&self) -> Option { + self.base.parent_type_id } fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "RegexBox({})", self.pattern.as_str()) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl std::fmt::Display for RegexBox { diff --git a/src/boxes/result/mod.rs b/src/boxes/result/mod.rs index fb7ea560..7fe7ce6b 100644 --- a/src/boxes/result/mod.rs +++ b/src/boxes/result/mod.rs @@ -51,9 +51,6 @@ impl NyashBox for NyashResultBox { } } - fn as_any(&self) -> &dyn Any { - self - } fn type_name(&self) -> &'static str { "NyashResultBox" @@ -81,6 +78,14 @@ impl BoxCore for NyashResultBox { NyashResultBox::Err(err) => err.box_id(), } } + + fn parent_type_id(&self) -> Option { + // For enum variants, we use the contained value's parent type ID + match self { + NyashResultBox::Ok(val) => val.parent_type_id(), + NyashResultBox::Err(err) => err.parent_type_id(), + } + } fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -88,6 +93,14 @@ impl BoxCore for NyashResultBox { NyashResultBox::Err(err) => write!(f, "Err({})", err.to_string_box().value), } } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl std::fmt::Display for NyashResultBox { diff --git a/src/boxes/simple_intent_box.rs b/src/boxes/simple_intent_box.rs index 7a059bd6..25df769b 100644 --- a/src/boxes/simple_intent_box.rs +++ b/src/boxes/simple_intent_box.rs @@ -159,33 +159,46 @@ * - 本格P2P実装は将来バージョンで提供予定 */ -use crate::box_trait::{NyashBox, StringBox, BoolBox}; +use crate::box_trait::{NyashBox, StringBox, BoolBox, BoxCore, BoxBase}; use std::any::Any; use std::sync::{Arc, Mutex}; use std::collections::HashMap; #[derive(Debug)] pub struct SimpleIntentBox { - id: u64, + base: BoxBase, // ノードID -> コールバック関数のマップ listeners: Arc>>>, // 仮実装 } impl SimpleIntentBox { pub fn new() -> Self { - static mut COUNTER: u64 = 0; - let id = unsafe { - COUNTER += 1; - COUNTER - }; - SimpleIntentBox { - id, + base: BoxBase::new(), listeners: Arc::new(Mutex::new(HashMap::new())), } } } +impl BoxCore for SimpleIntentBox { + fn box_id(&self) -> u64 { + self.base.id + } + + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "SimpleIntentBox(id: {}))", self.base.id) + } + + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} + impl NyashBox for SimpleIntentBox { fn to_string_box(&self) -> StringBox { StringBox::new("IntentBox") @@ -193,7 +206,7 @@ impl NyashBox for SimpleIntentBox { fn equals(&self, other: &dyn NyashBox) -> BoolBox { if let Some(other_intent) = other.as_any().downcast_ref::() { - BoolBox::new(self.id == other_intent.id) + BoolBox::new(self.base.id == other_intent.base.id) } else { BoolBox::new(false) } @@ -206,16 +219,15 @@ impl NyashBox for SimpleIntentBox { fn clone_box(&self) -> Box { // IntentBoxは共有されるので、新しいインスタンスを作らない Box::new(SimpleIntentBox { - id: self.id, + base: BoxBase::new(), // Create new base with unique ID for clone listeners: self.listeners.clone(), }) } - fn as_any(&self) -> &dyn Any { - self - } - - fn box_id(&self) -> u64 { - self.id +} + +impl std::fmt::Display for SimpleIntentBox { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.fmt_box(f) } } \ No newline at end of file diff --git a/src/boxes/sound_box.rs b/src/boxes/sound_box.rs index ceaa85da..dd18fd49 100644 --- a/src/boxes/sound_box.rs +++ b/src/boxes/sound_box.rs @@ -334,9 +334,6 @@ impl NyashBox for SoundBox { } } - fn as_any(&self) -> &dyn Any { - self - } } @@ -345,9 +342,21 @@ impl BoxCore for SoundBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "SoundBox()") } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl Display for SoundBox { diff --git a/src/boxes/stream/mod.rs b/src/boxes/stream/mod.rs index ac598c36..32d0f73e 100644 --- a/src/boxes/stream/mod.rs +++ b/src/boxes/stream/mod.rs @@ -147,9 +147,6 @@ impl NyashBox for NyashStreamBox { StringBox::new(format!("NyashStreamBox({} bytes, pos: {})", buffer.len(), *position)) } - fn as_any(&self) -> &dyn Any { - self - } fn type_name(&self) -> &'static str { "NyashStreamBox" @@ -171,7 +168,11 @@ impl NyashBox for NyashStreamBox { impl BoxCore for NyashStreamBox { fn box_id(&self) -> u64 { - self.base.id() + self.base.id + } + + fn parent_type_id(&self) -> Option { + self.base.parent_type_id } fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -179,6 +180,14 @@ impl BoxCore for NyashStreamBox { let position = self.position.lock().unwrap(); write!(f, "NyashStreamBox({} bytes, pos: {})", buffer.len(), *position) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl std::fmt::Display for NyashStreamBox { diff --git a/src/boxes/string_box.rs b/src/boxes/string_box.rs index bae41ff9..e9a401f0 100644 --- a/src/boxes/string_box.rs +++ b/src/boxes/string_box.rs @@ -151,9 +151,6 @@ impl NyashBox for StringBox { Box::new(self.clone()) } - fn as_any(&self) -> &dyn Any { - self - } } @@ -162,9 +159,21 @@ impl BoxCore for StringBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.value) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl Display for StringBox { diff --git a/src/boxes/time_box.rs b/src/boxes/time_box.rs index 8e05c612..738239ab 100644 --- a/src/boxes/time_box.rs +++ b/src/boxes/time_box.rs @@ -208,9 +208,6 @@ impl NyashBox for TimeBox { } } - fn as_any(&self) -> &dyn Any { - self - } } impl BoxCore for TimeBox { @@ -218,9 +215,21 @@ impl BoxCore for TimeBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "TimeBox()") } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl Display for TimeBox { @@ -370,9 +379,6 @@ impl NyashBox for DateTimeBox { } } - fn as_any(&self) -> &dyn Any { - self - } } impl BoxCore for DateTimeBox { @@ -380,9 +386,21 @@ impl BoxCore for DateTimeBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.datetime.format("%Y-%m-%d %H:%M:%S")) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl Display for DateTimeBox { @@ -445,9 +463,6 @@ impl NyashBox for TimerBox { } } - fn as_any(&self) -> &dyn Any { - self - } } impl BoxCore for TimerBox { @@ -455,9 +470,21 @@ impl BoxCore for TimerBox { self.base.id } + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "TimerBox()") } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl Display for TimerBox { diff --git a/src/boxes/web/web_canvas_box.rs b/src/boxes/web/web_canvas_box.rs index 4e7655b6..4fff177a 100644 --- a/src/boxes/web/web_canvas_box.rs +++ b/src/boxes/web/web_canvas_box.rs @@ -5,7 +5,7 @@ * ピクセルの世界を制圧する革命的Box! */ -use crate::box_trait::{NyashBox, StringBox, BoolBox}; +use crate::box_trait::{NyashBox, StringBox, BoolBox, BoxCore, BoxBase}; use std::any::Any; #[cfg(target_arch = "wasm32")] @@ -21,7 +21,7 @@ use web_sys::{ #[cfg(target_arch = "wasm32")] #[derive(Debug, Clone)] pub struct WebCanvasBox { - id: u64, + base: BoxBase, canvas_id: String, width: u32, height: u32, @@ -30,14 +30,8 @@ pub struct WebCanvasBox { #[cfg(target_arch = "wasm32")] impl WebCanvasBox { pub fn new(canvas_id: String, width: u32, height: u32) -> Self { - static mut COUNTER: u64 = 0; - let id = unsafe { - COUNTER += 1; - COUNTER - }; - let instance = Self { - id, + base: BoxBase::new(), canvas_id: canvas_id.clone(), width, height, @@ -267,6 +261,26 @@ impl WebCanvasBox { } } +#[cfg(target_arch = "wasm32")] +impl BoxCore for WebCanvasBox { + fn box_id(&self) -> u64 { + self.base.id + } + + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "WebCanvasBox({}, {}x{})", self.canvas_id, self.width, self.height) + } + + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} + #[cfg(target_arch = "wasm32")] impl NyashBox for WebCanvasBox { fn clone_box(&self) -> Box { @@ -282,23 +296,24 @@ impl NyashBox for WebCanvasBox { )) } - fn as_any(&self) -> &dyn Any { - self - } fn type_name(&self) -> &'static str { "WebCanvasBox" } - fn box_id(&self) -> u64 { - self.id - } fn equals(&self, other: &dyn NyashBox) -> BoolBox { if let Some(other_canvas) = other.as_any().downcast_ref::() { - BoolBox::new(self.id == other_canvas.id) + BoolBox::new(self.base.id == other_canvas.base.id) } else { BoolBox::new(false) } } +} + +#[cfg(target_arch = "wasm32")] +impl std::fmt::Display for WebCanvasBox { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.fmt_box(f) + } } \ No newline at end of file diff --git a/src/boxes/web/web_console_box.rs b/src/boxes/web/web_console_box.rs index 89c94dba..041478e6 100644 --- a/src/boxes/web/web_console_box.rs +++ b/src/boxes/web/web_console_box.rs @@ -5,7 +5,7 @@ * F12コンソールの代わりに指定要素に出力 */ -use crate::box_trait::{NyashBox, StringBox, BoolBox}; +use crate::box_trait::{NyashBox, StringBox, BoolBox, BoxCore, BoxBase}; use std::any::Any; #[cfg(target_arch = "wasm32")] @@ -18,20 +18,15 @@ use web_sys::{Element, HtmlElement}; #[cfg(target_arch = "wasm32")] #[derive(Debug, Clone)] pub struct WebConsoleBox { - id: u64, + base: BoxBase, target_element_id: String, } #[cfg(target_arch = "wasm32")] impl WebConsoleBox { pub fn new(element_id: String) -> Self { - static mut COUNTER: u64 = 0; - let id = unsafe { - COUNTER += 1; - COUNTER - }; Self { - id, + base: BoxBase::new(), target_element_id: element_id, } } @@ -143,6 +138,26 @@ impl WebConsoleBox { } } +#[cfg(target_arch = "wasm32")] +impl BoxCore for WebConsoleBox { + fn box_id(&self) -> u64 { + self.base.id + } + + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "WebConsoleBox({})", self.target_element_id) + } + + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} + #[cfg(target_arch = "wasm32")] impl NyashBox for WebConsoleBox { fn clone_box(&self) -> Box { @@ -153,23 +168,24 @@ impl NyashBox for WebConsoleBox { StringBox::new(format!("WebConsoleBox({})", self.target_element_id)) } - fn as_any(&self) -> &dyn Any { - self - } fn type_name(&self) -> &'static str { "WebConsoleBox" } - fn box_id(&self) -> u64 { - self.id - } fn equals(&self, other: &dyn NyashBox) -> BoolBox { if let Some(other_console) = other.as_any().downcast_ref::() { - BoolBox::new(self.id == other_console.id) + BoolBox::new(self.base.id == other_console.base.id) } else { BoolBox::new(false) } } +} + +#[cfg(target_arch = "wasm32")] +impl std::fmt::Display for WebConsoleBox { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.fmt_box(f) + } } \ No newline at end of file diff --git a/src/boxes/web/web_display_box.rs b/src/boxes/web/web_display_box.rs index ff3cc61c..13b8c77f 100644 --- a/src/boxes/web/web_display_box.rs +++ b/src/boxes/web/web_display_box.rs @@ -5,7 +5,7 @@ * プレイグラウンドの出力パネル等を完全制御 */ -use crate::box_trait::{NyashBox, StringBox, BoolBox}; +use crate::box_trait::{NyashBox, StringBox, BoolBox, BoxCore, BoxBase}; use std::any::Any; #[cfg(target_arch = "wasm32")] @@ -18,20 +18,15 @@ use web_sys::{Element, HtmlElement}; #[cfg(target_arch = "wasm32")] #[derive(Debug, Clone)] pub struct WebDisplayBox { - id: u64, + base: BoxBase, target_element_id: String, } #[cfg(target_arch = "wasm32")] impl WebDisplayBox { pub fn new(element_id: String) -> Self { - static mut COUNTER: u64 = 0; - let id = unsafe { - COUNTER += 1; - COUNTER - }; Self { - id, + base: BoxBase::new(), target_element_id: element_id, } } @@ -136,6 +131,26 @@ impl WebDisplayBox { } } +#[cfg(target_arch = "wasm32")] +impl BoxCore for WebDisplayBox { + fn box_id(&self) -> u64 { + self.base.id + } + + fn parent_type_id(&self) -> Option { + self.base.parent_type_id + } + + fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "WebDisplayBox({})", self.target_element_id) + } + + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} + #[cfg(target_arch = "wasm32")] impl NyashBox for WebDisplayBox { fn clone_box(&self) -> Box { @@ -146,24 +161,24 @@ impl NyashBox for WebDisplayBox { StringBox::new(format!("WebDisplayBox({})", self.target_element_id)) } - fn as_any(&self) -> &dyn Any { - self - } fn type_name(&self) -> &'static str { "WebDisplayBox" } - fn box_id(&self) -> u64 { - self.id - } fn equals(&self, other: &dyn NyashBox) -> BoolBox { if let Some(other_display) = other.as_any().downcast_ref::() { - BoolBox::new(self.id == other_display.id) + BoolBox::new(self.base.id == other_display.base.id) } else { BoolBox::new(false) } } +} +#[cfg(target_arch = "wasm32")] +impl std::fmt::Display for WebDisplayBox { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.fmt_box(f) + } } \ No newline at end of file diff --git a/src/channel_box.rs b/src/channel_box.rs index 1e34e151..00c61aaa 100644 --- a/src/channel_box.rs +++ b/src/channel_box.rs @@ -131,20 +131,29 @@ impl NyashBox for ChannelBox { } } - fn as_any(&self) -> &dyn Any { - self - } } impl BoxCore for ChannelBox { fn box_id(&self) -> u64 { - self.base.id() + self.base.id + } + + fn parent_type_id(&self) -> Option { + self.base.parent_type_id } fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Channel({} >> {})", self.sender_name, self.receiver_name) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl Display for ChannelBox { @@ -158,7 +167,7 @@ impl Debug for ChannelBox { f.debug_struct("ChannelBox") .field("sender_name", &self.sender_name) .field("receiver_name", &self.receiver_name) - .field("id", &self.base.id()) + .field("id", &self.base.id) .finish() } } @@ -187,7 +196,7 @@ impl NyashBox for MessageBox { } fn to_string_box(&self) -> StringBox { - StringBox::new(&format!("[{}] {}: {}", self.base.id(), self.sender, self.content)) + StringBox::new(&format!("[{}] {}: {}", self.base.id, self.sender, self.content)) } fn clone_box(&self) -> Box { @@ -205,19 +214,28 @@ impl NyashBox for MessageBox { } } - fn as_any(&self) -> &dyn Any { - self - } } impl BoxCore for MessageBox { fn box_id(&self) -> u64 { - self.base.id() + self.base.id + } + + fn parent_type_id(&self) -> Option { + self.base.parent_type_id } fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "[{}] {}: {}", self.base.id(), self.sender, self.content) + write!(f, "[{}] {}: {}", self.base.id, self.sender, self.content) + } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self } } diff --git a/src/exception_box.rs b/src/exception_box.rs index e0f12f5f..79661707 100644 --- a/src/exception_box.rs +++ b/src/exception_box.rs @@ -71,19 +71,28 @@ impl NyashBox for ErrorBox { Box::new(self.clone()) } - fn as_any(&self) -> &dyn Any { - self - } } impl BoxCore for ErrorBox { fn box_id(&self) -> u64 { - self.base.id() + self.base.id + } + + fn parent_type_id(&self) -> Option { + self.base.parent_type_id } fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "ErrorBox({})", self.message) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl std::fmt::Display for ErrorBox { diff --git a/src/instance.rs b/src/instance.rs index 2df5bbe2..7e8b7519 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -137,13 +137,13 @@ impl InstanceBox { impl NyashBox for InstanceBox { fn to_string_box(&self) -> StringBox { - StringBox::new(format!("<{} instance #{}>", self.class_name, self.base.id())) + StringBox::new(format!("<{} instance #{}>", self.class_name, self.base.id)) } fn equals(&self, other: &dyn NyashBox) -> BoolBox { if let Some(other_instance) = other.as_any().downcast_ref::() { // 同じインスタンスIDなら等しい - BoolBox::new(self.base.id() == other_instance.base.id()) + BoolBox::new(self.base.id == other_instance.base.id) } else { BoolBox::new(false) } @@ -158,19 +158,28 @@ impl NyashBox for InstanceBox { Box::new(self.clone()) } - fn as_any(&self) -> &dyn Any { - self - } } impl BoxCore for InstanceBox { fn box_id(&self) -> u64 { - self.base.id() + self.base.id + } + + fn parent_type_id(&self) -> Option { + self.base.parent_type_id } fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "<{} instance #{}>", self.class_name, self.base.id()) + write!(f, "<{} instance #{}>", self.class_name, self.base.id) + } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self } } diff --git a/src/interpreter/expressions.rs b/src/interpreter/expressions.rs index c095590d..75e6f34c 100644 --- a/src/interpreter/expressions.rs +++ b/src/interpreter/expressions.rs @@ -9,6 +9,7 @@ use super::*; use crate::ast::UnaryOperator; use crate::boxes::{buffer::BufferBox, JSONBox, HttpClientBox, StreamBox, RegexBox, IntentBox, P2PBox}; +use crate::boxes::{MathBox, ConsoleBox, TimeBox, RandomBox, SoundBox, DebugBox, file::FileBox, MapBox}; use crate::operator_traits::OperatorResolver; // TODO: Fix NullBox import issue later // use crate::NullBox; @@ -342,7 +343,7 @@ impl NyashInterpreter { } // FileBox method calls - if let Some(file_box) = obj_value.as_any().downcast_ref::() { + if let Some(file_box) = obj_value.as_any().downcast_ref::() { return self.execute_file_method(file_box, method, arguments); } @@ -734,12 +735,28 @@ impl NyashInterpreter { if !is_valid_delegation { return Err(RuntimeError::InvalidOperation { - message: format!("Class '{}' does not delegate to '{}'. Use 'box {} : {}' to establish delegation.", + message: format!("Class '{}' does not delegate to '{}'. Use 'box {} from {}' to establish delegation.", current_class, parent, current_class, parent), }); } - // 3. 親クラスのBox宣言を取得 + // 🔥 ビルトインBoxかチェック + let is_builtin = matches!(parent, + "IntegerBox" | "StringBox" | "BoolBox" | "ArrayBox" | "MapBox" | + "FileBox" | "ResultBox" | "FutureBox" | "ChannelBox" | "MathBox" | + "TimeBox" | "DateTimeBox" | "TimerBox" | "RandomBox" | "SoundBox" | + "DebugBox" | "MethodBox" | "NullBox" | "ConsoleBox" | "FloatBox" | + "BufferBox" | "RegexBox" | "JSONBox" | "StreamBox" | "HTTPClientBox" | + "IntentBox" | "P2PBox" | "EguiBox" + ); + + if is_builtin { + // ビルトインBoxの場合、ロックを解放してからメソッド呼び出し + drop(box_declarations); + return self.execute_builtin_box_method(parent, method, current_instance_val.clone_box(), arguments); + } + + // 3. 親クラスのBox宣言を取得(ユーザー定義Boxの場合) let parent_box_decl = box_declarations.get(parent) .ok_or(RuntimeError::UndefinedClass { name: parent.to_string() @@ -886,4 +903,73 @@ impl NyashInterpreter { }) } } + + /// 🔥 ビルトインBoxのメソッド呼び出し + fn execute_builtin_box_method(&mut self, parent: &str, method: &str, current_instance: Box, arguments: &[ASTNode]) + -> Result, RuntimeError> { + + // ビルトインBoxのインスタンスを作成または取得 + // 現在のインスタンスからビルトインBoxのデータを取得し、ビルトインBoxとしてメソッド実行 + + match parent { + "StringBox" => { + // StringBoxのインスタンスを作成(デフォルト値) + let string_box = StringBox::new(""); + self.execute_string_method(&string_box, method, arguments) + } + "IntegerBox" => { + // IntegerBoxのインスタンスを作成(デフォルト値) + let integer_box = IntegerBox::new(0); + self.execute_integer_method(&integer_box, method, arguments) + } + "ArrayBox" => { + let array_box = ArrayBox::new(); + self.execute_array_method(&array_box, method, arguments) + } + "MapBox" => { + let map_box = MapBox::new(); + self.execute_map_method(&map_box, method, arguments) + } + "MathBox" => { + let math_box = MathBox::new(); + self.execute_math_method(&math_box, method, arguments) + } + "P2PBox" => { + // P2PBoxの場合、現在のインスタンスからP2PBoxインスタンスを取得する必要がある + // TODO: 現在のインスタンスのフィールドからP2PBoxを取得 + return Err(RuntimeError::InvalidOperation { + message: format!("P2PBox delegation not yet fully implemented: {}.{}", parent, method), + }); + } + "FileBox" => { + let file_box = crate::boxes::file::FileBox::new(); + self.execute_file_method(&file_box, method, arguments) + } + "ConsoleBox" => { + let console_box = ConsoleBox::new(); + self.execute_console_method(&console_box, method, arguments) + } + "TimeBox" => { + let time_box = TimeBox::new(); + self.execute_time_method(&time_box, method, arguments) + } + "RandomBox" => { + let random_box = RandomBox::new(); + self.execute_random_method(&random_box, method, arguments) + } + "DebugBox" => { + let debug_box = DebugBox::new(); + self.execute_debug_method(&debug_box, method, arguments) + } + "SoundBox" => { + let sound_box = SoundBox::new(); + self.execute_sound_method(&sound_box, method, arguments) + } + _ => { + Err(RuntimeError::InvalidOperation { + message: format!("Unknown built-in Box type for delegation: {}", parent), + }) + } + } + } } \ No newline at end of file diff --git a/src/interpreter/methods/io_methods.rs b/src/interpreter/methods/io_methods.rs index 3fa89644..c6f82c4c 100644 --- a/src/interpreter/methods/io_methods.rs +++ b/src/interpreter/methods/io_methods.rs @@ -8,7 +8,8 @@ */ use super::super::*; -use crate::box_trait::{FileBox, ResultBox, StringBox, NyashBox}; +use crate::box_trait::{ResultBox, StringBox, NyashBox}; +use crate::boxes::file::FileBox; impl NyashInterpreter { /// FileBoxのメソッド呼び出しを実行 diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 923f888d..b0edc451 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -7,7 +7,7 @@ // Import all necessary dependencies use crate::ast::{ASTNode, BinaryOperator, CatchClause}; -use crate::box_trait::{NyashBox, StringBox, IntegerBox, BoolBox, VoidBox, AddBox, SubtractBox, MultiplyBox, DivideBox, CompareBox, ArrayBox, FileBox, ResultBox, ErrorBox, FutureBox}; +use crate::box_trait::{NyashBox, StringBox, IntegerBox, BoolBox, VoidBox, AddBox, SubtractBox, MultiplyBox, DivideBox, CompareBox, ArrayBox, FileBox, ResultBox, ErrorBox, FutureBox, BoxCore}; use crate::instance::InstanceBox; use crate::channel_box::ChannelBox; use crate::boxes::math_box::{MathBox, FloatBox, RangeBox}; diff --git a/src/interpreter/objects.rs b/src/interpreter/objects.rs index e1fd3065..642c0abb 100644 --- a/src/interpreter/objects.rs +++ b/src/interpreter/objects.rs @@ -836,26 +836,41 @@ impl NyashInterpreter { // 親クラスの継承チェーンを再帰的に解決 if let Some(parent_name) = &box_decl.extends { - let parent_decl = { - let box_decls = self.shared.box_declarations.read().unwrap(); - box_decls.get(parent_name) - .ok_or(RuntimeError::UndefinedClass { name: parent_name.clone() })? - .clone() - }; + // 🔥 ビルトインBoxかチェック + let is_builtin = matches!(parent_name.as_str(), + "IntegerBox" | "StringBox" | "BoolBox" | "ArrayBox" | "MapBox" | + "FileBox" | "ResultBox" | "FutureBox" | "ChannelBox" | "MathBox" | + "TimeBox" | "DateTimeBox" | "TimerBox" | "RandomBox" | "SoundBox" | + "DebugBox" | "MethodBox" | "NullBox" | "ConsoleBox" | "FloatBox" | + "BufferBox" | "RegexBox" | "JSONBox" | "StreamBox" | "HTTPClientBox" | + "IntentBox" | "P2PBox" | "EguiBox" + ); - // インターフェースは継承できない - if parent_decl.is_interface { - return Err(RuntimeError::InvalidOperation { - message: format!("Cannot extend interface '{}'. Use 'implements' instead.", parent_name), - }); + if is_builtin { + // ビルトインBoxの場合、フィールドやメソッドは継承しない + // (ビルトインBoxのメソッドはfrom構文でアクセス可能) + } else { + let parent_decl = { + let box_decls = self.shared.box_declarations.read().unwrap(); + box_decls.get(parent_name) + .ok_or(RuntimeError::UndefinedClass { name: parent_name.clone() })? + .clone() + }; + + // インターフェースは継承できない + if parent_decl.is_interface { + return Err(RuntimeError::InvalidOperation { + message: format!("Cannot extend interface '{}'. Use 'implements' instead.", parent_name), + }); + } + + // 親クラスの継承チェーンを再帰的に解決 + let (parent_fields, parent_methods) = self.resolve_inheritance(&parent_decl)?; + + // 親のフィールドとメソッドを追加 + all_fields.extend(parent_fields); + all_methods.extend(parent_methods); } - - // 親クラスの継承チェーンを再帰的に解決 - let (parent_fields, parent_methods) = self.resolve_inheritance(&parent_decl)?; - - // 親のフィールドとメソッドを追加 - all_fields.extend(parent_fields); - all_methods.extend(parent_methods); } // 現在のクラスのフィールドとメソッドを追加(オーバーライド可能) diff --git a/src/main.rs b/src/main.rs index 474363c6..32420636 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,7 +20,7 @@ pub mod method_box; pub mod operator_traits; pub mod box_operators; -use box_trait::{NyashBox, StringBox, IntegerBox, BoolBox, VoidBox, AddBox}; +use box_trait::{NyashBox, StringBox, IntegerBox, BoolBox, VoidBox, AddBox, BoxCore}; use environment::{Environment, PythonCompatEnvironment}; use tokenizer::{NyashTokenizer, TokenType}; use ast::ASTNode; diff --git a/src/method_box.rs b/src/method_box.rs index 1b4b9533..814f985b 100644 --- a/src/method_box.rs +++ b/src/method_box.rs @@ -119,20 +119,29 @@ impl NyashBox for MethodBox { Box::new(self.clone()) } - fn as_any(&self) -> &dyn Any { - self - } } impl BoxCore for MethodBox { fn box_id(&self) -> u64 { - self.base.id() + self.base.id + } + + fn parent_type_id(&self) -> Option { + self.base.parent_type_id } fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "", self.method_name) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl Display for MethodBox { diff --git a/src/type_box.rs b/src/type_box.rs index a5c473e9..9ce0b3fe 100644 --- a/src/type_box.rs +++ b/src/type_box.rs @@ -254,20 +254,29 @@ impl NyashBox for TypeBox { Box::new(self.clone()) } - fn as_any(&self) -> &dyn Any { - self - } } impl BoxCore for TypeBox { fn box_id(&self) -> u64 { - self.base.id() + self.base.id + } + + fn parent_type_id(&self) -> Option { + self.base.parent_type_id } fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "", self.full_name()) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl Display for TypeBox {