fix(joinir): Phase 241-EX - Remove hardcoded 'sum' check from Pattern3
Remove legacy hardcoded 'sum' carrier validation that was blocking array_filter patterns with different accumulator names (e.g., 'out'). Before: Pattern3 required carrier named 'sum' to exist After: Pattern3 uses carrier_info generically (any carrier name works) Test results: - phase49_joinir_array_filter_smoke: PASS ✅ - phase49_joinir_array_filter_fallback: PASS ✅ - phase49_joinir_array_filter_ab_comparison: PASS ✅ - Full suite: 909/909 PASS, 0 FAIL Also: Archive old roadmap documentation (67k lines moved to docs/archive/) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -1,241 +0,0 @@
|
||||
# 🌟 Nyash アーキテクチャ再設計提案
|
||||
|
||||
*by Codex exec (2025-08-21)*
|
||||
|
||||
## 🎯 核心的洞察
|
||||
|
||||
**「実装詳細共有」から「モデル共有・実行時共有」への転換**
|
||||
|
||||
現在の問題の本質は、InterpreterとVMが「実装詳細」を共有しようとしていること。正しいアプローチは「モデル(宣言)」と「ランタイム(実行環境)」を共有し、実行戦略だけを分離すること。
|
||||
|
||||
## 🏗️ 新アーキテクチャ層構造
|
||||
|
||||
```
|
||||
┌─────────────┐
|
||||
│ AST/Model │ ← 純粋なデータモデル(依存なし)
|
||||
└──────┬──────┘
|
||||
│
|
||||
┌──────▼──────┐
|
||||
│ Runtime │ ← 型システム・クラス管理・インスタンス生成
|
||||
└──────┬──────┘
|
||||
│
|
||||
┌──────┴──────┬──────────┬────────────┐
|
||||
│ Interpreter │ VM │ Plugins │
|
||||
└─────────────┴──────────┴────────────┘
|
||||
```
|
||||
|
||||
### 各層の責務
|
||||
|
||||
**AST/Model層**
|
||||
- 言語の純データモデル
|
||||
- BoxDeclaration、ASTNode、型シグネチャ
|
||||
- 実行時情報を含まない
|
||||
|
||||
**Runtime層**
|
||||
- BoxClass/BoxFactoryによる型システム
|
||||
- インスタンス生成とライフサイクル管理
|
||||
- メソッドディスパッチと呼び出し規約
|
||||
|
||||
**Backend層**
|
||||
- Interpreter: AST直接実行
|
||||
- VM: MIR/Bytecode実行
|
||||
- 両者ともRuntimeを通じてBoxを操作
|
||||
|
||||
## 🔧 具体的な設計
|
||||
|
||||
### 1. BoxDeclarationの移動
|
||||
|
||||
```rust
|
||||
// core::model::box_declaration.rs
|
||||
pub struct BoxDeclaration {
|
||||
pub name: String,
|
||||
pub type_params: Vec<TypeParam>,
|
||||
pub fields: Vec<FieldDecl>,
|
||||
pub methods: Vec<MethodDecl>,
|
||||
pub static_methods: Vec<StaticDecl>,
|
||||
pub attrs: AttrSet,
|
||||
pub source_span: Option<Span>,
|
||||
}
|
||||
|
||||
pub struct FieldDecl {
|
||||
pub name: String,
|
||||
pub ty: TypeRef,
|
||||
pub attrs: AttrSet,
|
||||
}
|
||||
|
||||
pub struct MethodDecl {
|
||||
pub name: String,
|
||||
pub sig: FnSig,
|
||||
pub body: FnBodyRef, // AST or MIR reference
|
||||
}
|
||||
```
|
||||
|
||||
### 2. NyashRuntimeの導入
|
||||
|
||||
```rust
|
||||
// runtime::mod.rs
|
||||
pub struct NyashRuntime {
|
||||
box_registry: BoxRegistry,
|
||||
type_space: TypeSpace,
|
||||
fn_space: FnSpace,
|
||||
}
|
||||
|
||||
pub struct ExecutionSession {
|
||||
runtime: Arc<NyashRuntime>,
|
||||
root_box: SharedBox,
|
||||
frames: Vec<Frame>,
|
||||
env: Environment,
|
||||
}
|
||||
|
||||
// SharedBox = Arc<dyn NyashBox>
|
||||
pub type SharedBox = Arc<dyn NyashBox>;
|
||||
```
|
||||
|
||||
### 3. BoxClass/Factoryシステム
|
||||
|
||||
```rust
|
||||
// runtime::box_class.rs
|
||||
pub trait BoxClass: Send + Sync {
|
||||
fn name(&self) -> &str;
|
||||
fn instantiate(
|
||||
&self,
|
||||
args: &[SharedBox],
|
||||
sess: &mut ExecutionSession
|
||||
) -> Result<SharedBox>;
|
||||
fn lookup_method(&self, name: &str) -> Option<MethodHandle>;
|
||||
fn lifecycle(&self) -> Option<&dyn BoxLifecycle>;
|
||||
}
|
||||
|
||||
pub trait BoxFactory: Send + Sync {
|
||||
fn can_build(&self, decl: &BoxDeclaration) -> bool;
|
||||
fn build_class(
|
||||
&self,
|
||||
decl: &BoxDeclaration,
|
||||
rt: &NyashRuntime
|
||||
) -> Result<Arc<dyn BoxClass>>;
|
||||
}
|
||||
|
||||
pub trait BoxLifecycle {
|
||||
fn on_birth(&self, ctx: &mut InstanceCtx) -> Result<()>;
|
||||
fn on_fini(&self, ctx: &mut InstanceCtx);
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 統一されたBox管理
|
||||
|
||||
```rust
|
||||
// runtime::registry.rs
|
||||
pub struct BoxRegistry {
|
||||
classes: RwLock<HashMap<String, Arc<dyn BoxClass>>>,
|
||||
factories: RwLock<Vec<Arc<dyn BoxFactory>>>,
|
||||
}
|
||||
|
||||
impl BoxRegistry {
|
||||
pub fn register_class(&self, class: Arc<dyn BoxClass>) {
|
||||
// 登録処理
|
||||
}
|
||||
|
||||
pub fn get_class(&self, name: &str) -> Option<Arc<dyn BoxClass>> {
|
||||
// クラス取得
|
||||
}
|
||||
|
||||
pub fn create_instance(
|
||||
&self,
|
||||
class_name: &str,
|
||||
args: &[SharedBox],
|
||||
sess: &mut ExecutionSession
|
||||
) -> Result<SharedBox> {
|
||||
let class = self.get_class(class_name)?;
|
||||
class.instantiate(args, sess)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📋 実装手順(最小破壊的移行)
|
||||
|
||||
### Step 1: BoxDeclarationの移動
|
||||
```rust
|
||||
// 1. core::model モジュールを作成
|
||||
// 2. BoxDeclarationを移動
|
||||
// 3. インタープリターで一時的に別名を使用
|
||||
use core::model::BoxDeclaration as InterpreterBoxDecl;
|
||||
```
|
||||
|
||||
### Step 2: NyashRuntimeの骨組み作成
|
||||
```rust
|
||||
// 最初は空の実装から始める
|
||||
pub struct NyashRuntime {
|
||||
// 段階的に追加
|
||||
}
|
||||
|
||||
pub struct NyashRuntimeBuilder {
|
||||
// SharedStateからの移行を支援
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: BoxFactoryのdyn化
|
||||
```rust
|
||||
// 現在の trait BoxFactory を使用
|
||||
// すべて Arc<dyn BoxFactory> として扱う
|
||||
```
|
||||
|
||||
### Step 4: グローバル登録の排除
|
||||
```rust
|
||||
// 削除: register_user_defined_factory(...)
|
||||
// 追加: NyashRuntimeBuilder::with_factory(...)
|
||||
```
|
||||
|
||||
### Step 5: SharedStateの段階的分解
|
||||
```rust
|
||||
// 一時的なシム
|
||||
pub struct SharedStateShim {
|
||||
runtime: Arc<NyashRuntime>,
|
||||
session: ExecutionSession,
|
||||
}
|
||||
|
||||
// 互換性のためのFrom実装
|
||||
impl From<SharedState> for SharedStateShim {
|
||||
// 移行ロジック
|
||||
}
|
||||
```
|
||||
|
||||
### Step 6-8: 統一と最適化
|
||||
- Interpreter/VMのコンストラクタ統一
|
||||
- birth/finiライフサイクルの一元化
|
||||
- 最終的なSharedState削除
|
||||
|
||||
## 🎯 得られる利点
|
||||
|
||||
1. **依存関係の明確化**
|
||||
- VM→Interpreter依存が完全に解消
|
||||
- 両者はRuntimeのみに依存
|
||||
|
||||
2. **テスタビリティ向上**
|
||||
- グローバル状態なし
|
||||
- 並行テスト可能
|
||||
|
||||
3. **保守性向上**
|
||||
- 責務が明確に分離
|
||||
- 新しいBackend追加が容易
|
||||
|
||||
4. **Everything is Box哲学の貫徹**
|
||||
- 統一的なBox管理
|
||||
- birth/finiライフサイクルの一元化
|
||||
|
||||
## ⚠️ 実装上の注意点
|
||||
|
||||
1. **trait objectは必ず`Arc<dyn Trait>`**
|
||||
- `Arc<Trait>`は使わない
|
||||
- dynキーワードを忘れない
|
||||
|
||||
2. **段階的移行**
|
||||
- 各ステップでテストが通ることを確認
|
||||
- 互換性レイヤーを活用
|
||||
|
||||
3. **ロックの最小化**
|
||||
- Runtimeは基本的に不変
|
||||
- 必要最小限のRwLock使用
|
||||
|
||||
---
|
||||
|
||||
この設計により、Nyashはよりシンプルでエレガントなアーキテクチャとなり、InterpreterとVMの統合が自然に実現されます。
|
||||
@ -1,5 +1,8 @@
|
||||
# Comprehensive Rust Code Refactoring Discovery
|
||||
|
||||
Status: Active
|
||||
Scope: Rust コード全体のリファクタリング候補を洗い出した調査結果の現行まとめ(2025-12-05 時点)。
|
||||
|
||||
**Date**: 2025-12-05
|
||||
**Scope**: Entire `/home/tomoaki/git/hakorune-selfhost/src` directory
|
||||
**Methodology**: Line count + complexity analysis + activity analysis + Phase 188 context
|
||||
|
||||
@ -1,77 +0,0 @@
|
||||
# Nyash Concurrency — Box Model (Proposal, docs-only)
|
||||
|
||||
Status: design-only during the feature‑pause. No runtime or spec changes. Implement after Mini‑VM baseline is stable.
|
||||
|
||||
Intent
|
||||
- Bring Go-like CSP (goroutine/channels/select) into Nyash via “Everything is Box”.
|
||||
- Keep semantics explicit, lifecycle safe (birth/fini), and observable. Phase-in from userland → runtime.
|
||||
|
||||
Scope (Phase‑0: userland MVP)
|
||||
- RoutineBox: lightweight task wrapper over `nowait` (state, join/cancel, status).
|
||||
- ChannelBox: bounded/unbounded queue + blocking/non-blocking ops + close semantics.
|
||||
- SelectBox: multi-channel wait (first-ready) with simple fairness.
|
||||
- RoutineScopeBox: structured concurrency; children are canceled on scope fini.
|
||||
- Observability: JSONL trace toggled by `NYASH_CONC_TRACE=1`.
|
||||
|
||||
Non‑Goals (Phase‑0)
|
||||
- M:N scheduler, OS-level park/unpark, net poller integration (deferred to Phase‑2 runtime work).
|
||||
|
||||
API Sketch (userland)
|
||||
- RoutineBox
|
||||
- birth(fn)
|
||||
- start(): Void
|
||||
- join(timeout_ms?: Int) -> Bool // true if joined; false on timeout
|
||||
- cancel(): Void
|
||||
- status() -> String // ready|running|done|canceled|error
|
||||
- ChannelBox(capacity: Int=0)
|
||||
- send(v): Void // blocks if full (Phase‑0: simulated park)
|
||||
- try_send(v) -> Bool
|
||||
- receive() -> Any // blocks if empty (Phase‑0: simulated park)
|
||||
- try_receive() -> (Bool, Any?)
|
||||
- receive_timeout(ms: Int) -> (Bool, Any?)
|
||||
- close(): Void // further send fails; recv drains until empty then End
|
||||
- SelectBox
|
||||
- birth()
|
||||
- when(ch: ChannelBox, handler: Fn): Void
|
||||
- await() -> Bool // returns after one handler runs; false if none ready and no wait policy
|
||||
- await_timeout(ms: Int) -> Bool
|
||||
- RoutineScopeBox
|
||||
- birth()
|
||||
- spawn(fn) -> RoutineBox
|
||||
- fini() // cancels pending routines and waits boundedly
|
||||
|
||||
Semantics
|
||||
- Capacity:
|
||||
- 0: rendezvous channel (send/recv rendezvous).
|
||||
- N>0: bounded ring buffer.
|
||||
- Close:
|
||||
- close() marks channel as closed. send() after close -> error. receive() returns buffered items; when empty -> (false, End) style result; exact return shape defined per API.
|
||||
- Blocking:
|
||||
- Phase‑0 userland uses cooperative wait queues; no busy loops. try_* and timeout variants provided.
|
||||
- Select fairness:
|
||||
- If multiple ready, choose random/round‑robin. Starvation avoidance is a design requirement; precise algorithm can evolve.
|
||||
- Types:
|
||||
- `TypedChannelBox<T>` is a future extension; Phase‑0 uses runtime tags/guards documented in reference.
|
||||
- Cancellation:
|
||||
- RoutineScopeBox cancels children on fini; Channel waits should return (canceled) promptly.
|
||||
|
||||
Phases
|
||||
- Phase‑0 (userland MVP / PyVM first)
|
||||
- Implement the 4 boxes above with minimal queues/waits, plus trace hooks.
|
||||
- Smokes: ping‑pong, bounded producer/consumer, two‑way select, close semantics, scope cancel.
|
||||
- Phase‑1 (park/unpark abstraction)
|
||||
- Introduce `WaiterBox`/`CondBox` that map to efficient OS waits where available. Keep same APIs.
|
||||
- Phase‑2 (runtime integration)
|
||||
- Scheduler (M:N), GC and net poller integration, fairness and profiling. Keep Box APIs stable.
|
||||
|
||||
Observability
|
||||
- `NYASH_CONC_TRACE=1` → JSONL events: spawn/join/cancel/send/recv/park/unpark/select/close with routine IDs, channel IDs, timestamps.
|
||||
|
||||
Safety & Diagnostics
|
||||
- Deadlock hints: trace dependent waits; optional detector (dev only) can dump wait‑for graph.
|
||||
- API contracts explicitly define error return for misuse (send on closed, double close, etc.).
|
||||
|
||||
Deliverables (docs‑only during the feature‑pause)
|
||||
- This proposal (boxes & semantics).
|
||||
- Reference page with blocking/close/select rules (see reference/concurrency/semantics.md).
|
||||
- Test plan with named smokes and expected outputs.
|
||||
@ -1,158 +0,0 @@
|
||||
# 純粋関数型[]ブロック vs 通常{}ブロック設計案
|
||||
|
||||
## 概要
|
||||
|
||||
Nyashにおける**{}ローカルスコープ**と**[]純粋スコープ**の明確な差別化設計。
|
||||
「すべてはBox」哲学の中で、副作用を含む通常処理と純粋関数型処理を共存させる革命的アプローチ。
|
||||
|
||||
## 基本的な差別化
|
||||
|
||||
### {}ブロック(既存)- 通常のNyashスコープ
|
||||
```nyash
|
||||
{
|
||||
local counter = new IntegerBox(0) // Box生成OK
|
||||
counter.set(counter.get() + 1) // 副作用OK
|
||||
SomeGlobalBox.modify() // 外部状態変更OK
|
||||
ChannelBox.send("data") // I/O副作用OK
|
||||
// 普通のNyash文法、制約なし
|
||||
}
|
||||
```
|
||||
|
||||
### []ブロック(提案)- 純粋関数型スコープ
|
||||
```nyash
|
||||
[
|
||||
// コンパイラが以下を厳密にチェック:
|
||||
input.map(x => x * 2) // ✅ 純粋変換のみ
|
||||
.filter(x => x > 10) // ✅ 副作用なし
|
||||
.reduce((a, b) => a + b, 0) // ✅ 参照透過性保証
|
||||
|
||||
// 以下はコンパイルエラー:
|
||||
// SomeBox.mutate() // ❌ 外部状態変更禁止
|
||||
// print("debug") // ❌ I/O副作用禁止
|
||||
// local x = 1; x = 2 // ❌ 変数再代入禁止
|
||||
]
|
||||
```
|
||||
|
||||
## 深い差別化ポイント
|
||||
|
||||
### 1. コンパイラレベルの制約
|
||||
- **{}**: 制約なし、通常のNyash文法
|
||||
- **[]**: 厳密な純粋性チェック、副作用検出でコンパイルエラー
|
||||
|
||||
### 2. メモリモデル
|
||||
- **{}**: 新しいBoxの生成・変更可能
|
||||
- **[]**: 既存データの変換のみ、新しい状態作成禁止
|
||||
|
||||
### 3. 並行安全性
|
||||
- **{}**: データ競合の可能性あり
|
||||
- **[]**: 副作用なしなので自動的にthread-safe
|
||||
|
||||
### 4. 最適化
|
||||
- **{}**: 通常の最適化
|
||||
- **[]**: コンパイラが大胆な最適化可能(純粋性保証されているため)
|
||||
|
||||
### 5. デバッグ性
|
||||
- **{}**: 通常のデバッガ
|
||||
- **[]**: 入力→出力のみ追跡すればOK、デバッグ超簡単
|
||||
|
||||
## 実用的な使い分け例
|
||||
|
||||
```nyash
|
||||
box DataProcessor {
|
||||
processData(input: ArrayBox) -> ArrayBox {
|
||||
// 通常の{}スコープ: 準備・後処理
|
||||
{
|
||||
local logger = new LoggerBox()
|
||||
logger.info("Processing started")
|
||||
|
||||
// 純粋な[]スコープ: コア計算
|
||||
local result = [
|
||||
input
|
||||
.filter(x => x > 0)
|
||||
.map(x => Math.sqrt(x))
|
||||
.sort()
|
||||
]
|
||||
|
||||
logger.info("Processing completed")
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## []ブロックの真の価値
|
||||
|
||||
### 1. 数学的証明可能性
|
||||
[]内の処理は数学的に証明できる
|
||||
|
||||
### 2. 完全な再現性
|
||||
同じ入力→必ず同じ出力
|
||||
|
||||
### 3. 並列化自動最適化
|
||||
コンパイラが自動で並列化可能
|
||||
|
||||
### 4. ホットスワップ可能
|
||||
実行中でも[]部分だけ安全に入れ替え可能
|
||||
|
||||
## Box化による実装戦略
|
||||
|
||||
### PureCalculatorBox例
|
||||
```nyash
|
||||
box PureCalculatorBox {
|
||||
birth() { /* 状態なし、初期化も最小限 */ }
|
||||
|
||||
calculate(input: ArrayBox) -> ArrayBox {
|
||||
// []ブロックを使って、純粋性を言語レベルで保証
|
||||
local result = [
|
||||
input.map(x => x * 2).filter(x => x > 10)
|
||||
]
|
||||
return result
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### コンパイラもBox化
|
||||
「[]だけ解析する箱をつくる」アプローチ:
|
||||
- `PurityCheckerBox`: []ブロックの純粋性を厳密チェック
|
||||
- `ParserBox`: []専用構文解析
|
||||
- `OptimizerBox`: []専用最適化
|
||||
|
||||
## 哲学的統合
|
||||
|
||||
### {}ブロックと[]ブロックの共存
|
||||
- **{}**: "現実世界とのインターフェース"(副作用、状態管理)
|
||||
- **[]**: "純粋な計算の核心"(ロジック、変換、計算)
|
||||
|
||||
この差別化により、Nyashは:
|
||||
- **実用性** ({}での柔軟な状態管理)
|
||||
- **数学的美しさ** ([]での純粋性)
|
||||
|
||||
という**矛盾する要求を同時に満たす**ことができる。
|
||||
|
||||
## 「すべてはBox」哲学との整合性
|
||||
|
||||
これは「すべてはBox」哲学を破るのではなく、**異なる種類のBox(副作用Box vs 純粋Box)を明確に分離**する革命的なアプローチ。
|
||||
|
||||
- 副作用のあるBoxは{}内で使用
|
||||
- 純粋なBoxは[]内で使用
|
||||
- それぞれのBoxが適切なスコープで最大限の力を発揮
|
||||
|
||||
## 実装上の課題と解決策
|
||||
|
||||
### 課題
|
||||
1. コンパイラの複雑性増加
|
||||
2. []と{}間のデータやり取り
|
||||
3. エラーメッセージの分かりやすさ
|
||||
|
||||
### 解決策
|
||||
1. Box化されたコンパイラ(PurityCheckerBox等)で複雑性を分離
|
||||
2. 明確なデータ変換API([]→{}は常に安全、{}→[]は純粋性チェック)
|
||||
3. 文脈に応じた専用エラーメッセージ
|
||||
|
||||
## 結論
|
||||
|
||||
この設計により、Nyashは純粋関数型プログラミングの利点を享受しつつ、実用的な副作用処理も自然に行える、世界初の「ハイブリッド純粋言語」となる可能性がある。
|
||||
|
||||
**Date**: 2025-09-22
|
||||
**Status**: アイデア段階
|
||||
**Priority**: Phase 16以降での検討推奨
|
||||
@ -1,40 +0,0 @@
|
||||
# CAX (C-ABI Explorer) - Revolutionary Debugging Tool
|
||||
|
||||
**Status**: Post‑Bootstrap Implementation (Core Idea Complete)
|
||||
**Priority**: High (World-First Tool)
|
||||
**Origin**: 1-minute inspiration (C ABI dynamic → C ABI Debugger)
|
||||
**Date**: 2025-09-21
|
||||
|
||||
## 🌟 Core Concept
|
||||
|
||||
C-ABI境界デバッグのGUIツール。**「ぽいっと付け外し」「視覚的ログ監視」「マクロ自動化」「ホットスワップ」**を実現。
|
||||
|
||||
### Revolutionary Aspects
|
||||
- **Nyash箱理論**でC境界を完全トレース
|
||||
- **Record/Replay**で回帰テスト・CI再現性
|
||||
- **GUI Explorer**でプラグイン管理
|
||||
- **Type Safety**境界での型検証・所有権チェック
|
||||
|
||||
## 📁 Files Structure
|
||||
|
||||
- `gemini-ipc-implementation.hako` - Geminiの172行実装コード
|
||||
- `chatgpt-design-spec.md` - ChatGPTの設計仕様
|
||||
- `inspiration-process.md` - 1分発想プロセスの記録
|
||||
- `technical-roadmap.md` - 実装ロードマップ(2週間MVP)
|
||||
|
||||
## 🎯 Implementation Priority
|
||||
|
||||
**Phase 1** (Post Mini-VM): IPC層 + Timeline GUI
|
||||
**Phase 2**: Record/Replay + Hot-swap
|
||||
**Phase 3**: Advanced Analytics + 可視化
|
||||
|
||||
## 💡 Technical Innovation
|
||||
|
||||
- **境界フック**: PluginHost.Invoke 層で完全インターセプト
|
||||
- **統一観測**: すべてのBoxで統一されたイベントログ
|
||||
- **型安全**: TypeBox境界での実時間検証
|
||||
- **構造化**: RoutineBox/ChannelBox での並行デバッグ
|
||||
|
||||
---
|
||||
|
||||
**Note**: このアイデアは、C ABI動的呼び出しからわずか1分で到達した革新的発想の記録です。
|
||||
@ -1,145 +0,0 @@
|
||||
# CAX Design Specification (ChatGPT Analysis)
|
||||
|
||||
**Generated by**: ChatGPT
|
||||
**Date**: 2025-09-21
|
||||
**Context**: 30分集中設計セッション
|
||||
|
||||
## 🎯 Core Vision
|
||||
|
||||
**Nyash C-ABI Explorer (CAX)** - GUIでC ABI境界を「ぽいっと付け外し」「視覚化」「録って再生」「スクリプトで自動化」
|
||||
|
||||
## 🏗️ Architecture Design
|
||||
|
||||
### Core + GUI 分離アーキテクチャ
|
||||
```
|
||||
Core (Rust/Nyash): 既存cabi-debuggerフック + IPCサーバ
|
||||
↕ JSON-RPC/WebSocket
|
||||
GUI (Tauri/Electron): Svelte/React/TypeScript フロントエンド
|
||||
```
|
||||
|
||||
### データフロー
|
||||
```
|
||||
PluginHost.Invoke → CABIDebugger → IPC → GUI Timeline
|
||||
C ABI Calls → Real-time Logs → JSON Stream → 可視化
|
||||
```
|
||||
|
||||
## 🎨 UX Design
|
||||
|
||||
### 画面レイアウト (5パネル構成)
|
||||
```
|
||||
┌─────────────┬─────────────────┬─────────────┐
|
||||
│ Explorer │ Live Timeline │ Inspector │
|
||||
│ (attach/detach) │ (call flow) │ (call details)│
|
||||
├─────────────┴─────────────────┴─────────────┤
|
||||
│ Record/Replay Controls │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Console & Macros (Scripts) │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 操作体験
|
||||
1. **1クリック Attach**: `map.so` の行をクリック→即時ログ流れる
|
||||
2. **色分け表示**: 緑=Ok、黄=by-name、赤=Err/timeout、紫=ownership警告
|
||||
3. **録画/再生**: ワンボタンでJSONL/TLV保存→プラグイン無しで再現
|
||||
4. **ホットスワップ**: `disable→quiesce→reload` をGUIウィザードで
|
||||
|
||||
## 🔧 Technical Features
|
||||
|
||||
### 1. Real-time Monitoring
|
||||
- **Live Timeline**: Swimlane(プラグイン別/スレッド別)
|
||||
- **Call Inspector**: 引数/戻り値/実行時間/ソース位置
|
||||
- **Filter System**: `outcome:warn plugin:map` 形式
|
||||
|
||||
### 2. Record/Replay System
|
||||
```json
|
||||
// ログ1行例
|
||||
{
|
||||
"ts": 1737153845.123456,
|
||||
"plugin": "map.so",
|
||||
"type_id": 17,
|
||||
"method": "get/1",
|
||||
"args": [{"str":"key"}],
|
||||
"ret": {"str":"value"},
|
||||
"outcome": "Ok",
|
||||
"elapsed_us": 87,
|
||||
"by_name": false,
|
||||
"site": {"file":"apps/x.hako","line":42}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Hot-Swap Management
|
||||
```
|
||||
安全手順: disable → wait(0 inflight) → fini → dlclose → dlopen → init → re-enable
|
||||
GUI支援: 進捗表示 + state snapshot/restore(任意)
|
||||
```
|
||||
|
||||
### 4. Macro Automation
|
||||
```nyash
|
||||
// CAX API例
|
||||
cax.filter({outcome:'warn'})
|
||||
cax.attach("map.so")
|
||||
cax.replay("trace.tlv")
|
||||
cax.hotswap("map.so", "/tmp/map_new.so")
|
||||
```
|
||||
|
||||
## 📋 Implementation Roadmap
|
||||
|
||||
### Week 1 (MVP Core)
|
||||
- ✅ IPCサーバ(subscribe/attach/detach)
|
||||
- ✅ Explorer + Timeline(基本表示)
|
||||
- ✅ Inspector(引数/戻り値表示)
|
||||
- ✅ 記録(JSONL形式)
|
||||
|
||||
### Week 2 (Advanced Features)
|
||||
- ✅ Signature Checker(extern宣言 vs 実装差分)
|
||||
- ✅ Record/Replay(ファイル形式)
|
||||
- ✅ 簡易マクロ(フィルタ・基本操作)
|
||||
- ✅ Hot-swap wizard(dry-run)
|
||||
|
||||
## 🎨 GUI Implementation
|
||||
|
||||
### Technology Stack
|
||||
- **Frontend**: Tauri + Svelte/React + TypeScript
|
||||
- **IPC**: JSON-RPC over WebSocket
|
||||
- **Styling**: TailwindCSS + 可視化ライブラリ
|
||||
|
||||
### Key Components
|
||||
```typescript
|
||||
// IPC API例
|
||||
interface CaxApi {
|
||||
subscribe(params: {plugins: string[], level: string}): void
|
||||
attach(params: {plugin: string}): void
|
||||
hotswap(params: {plugin: string, path: string}): void
|
||||
record: {
|
||||
start(params: {file: string}): void
|
||||
stop(): void
|
||||
}
|
||||
replay(params: {file: string, mode: string}): void
|
||||
}
|
||||
```
|
||||
|
||||
## 🚧 Risk Mitigation
|
||||
|
||||
### Performance
|
||||
- **オーバーヘッド**: 既定軽量(log sampling、構造化は遅延ダンプ)
|
||||
- **再入防止**: スレッドローカルで抑止
|
||||
|
||||
### Safety
|
||||
- **クラッシュ隔離**: detach≠dlclose(最初は"ロード専用")
|
||||
- **権限管理**: プロセス境界越えはエージェント方式
|
||||
|
||||
## 💡 Competitive Advantages
|
||||
|
||||
### vs 既存デバッガ
|
||||
- **境界特化**: C↔Nyash境界に最適化された可視化
|
||||
- **型安全**: TypeBox境界での実時間検証
|
||||
- **構造化**: ライフサイクル・所有権の一元観測
|
||||
|
||||
### Innovation Points
|
||||
- **Record/Replay**: ABIコール完全再現(回帰テスト革命)
|
||||
- **GUI Integration**: コマンドライン→GUI操作の体験革新
|
||||
- **Hot-Swap**: 無停止デバッグ・プラグイン更新
|
||||
|
||||
---
|
||||
|
||||
**Note**: この設計は、C ABI動的呼び出しからの1分発想を30分で具体化したもの。実装の現実性と革新性を両立した世界初級ツールの仕様です。
|
||||
@ -1,165 +0,0 @@
|
||||
// CAX IPC Implementation (Gemini Draft)
|
||||
// Generated by Gemini AI - 2025-09-21
|
||||
// 172 lines of production-ready Nyash code
|
||||
|
||||
// IpcServerBox - CAXのIPCサーバーのメインとなるBox
|
||||
// クライアント(GUI)からの接続を受け付け、CABIDebuggerBoxと連携
|
||||
box IpcServerBox {
|
||||
cabiDebugger: CABIDebuggerBox
|
||||
clientConnections: MapBox<String, ClientConnectionBox>
|
||||
|
||||
birth() {
|
||||
me.cabiDebugger = new CABIDebuggerBox()
|
||||
me.clientConnections = new MapBox()
|
||||
}
|
||||
|
||||
// IPCリスナーを開始するルーチン(メインスレッド)
|
||||
startIpcListener() {
|
||||
loop {
|
||||
// 新しいクライアント接続を待つ
|
||||
local clientConnection = me.acceptNewClientConnection()
|
||||
if clientConnection == null { break }
|
||||
|
||||
local clientId = clientConnection.id()
|
||||
me.clientConnections.set(clientId, clientConnection)
|
||||
|
||||
// 各クライアント用の処理ルーチンを起動
|
||||
local commandChannel = new ChannelBox()
|
||||
local logChannel = new ChannelBox()
|
||||
|
||||
// クライアントコマンド処理用ルーチン
|
||||
nowait {
|
||||
me.handleClientCommands(clientConnection, clientId, logChannel)
|
||||
}
|
||||
|
||||
// デバッガーログをクライアントに転送するルーチン
|
||||
nowait {
|
||||
me.forwardDebuggerLogsToClient(clientId, logChannel)
|
||||
}
|
||||
|
||||
// 接続切断時の清掃
|
||||
clientConnection.onClose(() => {
|
||||
me.clientConnections.remove(clientId)
|
||||
me.cabiDebugger.removeLogSubscriber(clientId)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// クライアントからのコマンドを処理するルーチン
|
||||
handleClientCommands(clientConnection: ClientConnectionBox, clientId: String, clientChannel: ChannelBox) {
|
||||
loop {
|
||||
local command = clientConnection.receiveCommand() // クライアントからコマンドを受信
|
||||
if command == null { break } // 接続が切れたらループを抜ける
|
||||
|
||||
when command.method {
|
||||
"subscribe" => {
|
||||
local logLevel = command.params.logLevel
|
||||
me.cabiDebugger.addLogSubscriber(clientId, clientChannel, logLevel)
|
||||
clientConnection.sendResponse(command.id, new OkBox())
|
||||
}
|
||||
"attach" => {
|
||||
local pluginId = command.params.pluginId
|
||||
me.cabiDebugger.attachPlugin(pluginId)
|
||||
clientConnection.sendResponse(command.id, new OkBox())
|
||||
}
|
||||
// ... その他のコマンド (detach, record.start, replayなど)
|
||||
else => {
|
||||
clientConnection.sendResponse(command.id, new ErrorBox("Unknown command"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// C ABIデバッガーからのログを特定のクライアントに転送するルーチン
|
||||
forwardDebuggerLogsToClient(clientId: String, clientChannel: ChannelBox) {
|
||||
loop {
|
||||
// CABIDebuggerBoxから、このクライアントID宛のログを取得する
|
||||
// 実際には、CABIDebuggerBoxがログを生成し、購読しているチャネルに送る形になる
|
||||
local logEntry = me.cabiDebugger.getLogEntryForClient(clientId)
|
||||
if logEntry == null { break } // ログがなければ待機または終了
|
||||
|
||||
clientChannel.send(logEntry) // クライアントにログを送信
|
||||
}
|
||||
}
|
||||
|
||||
// 抽象的なクライアント接続を受け付けるメソッド (具体的なIPC実装に依存)
|
||||
acceptNewClientConnection() -> ClientConnectionBox {
|
||||
// ここに新しいクライアント接続を受け付ける具体的なロジック
|
||||
// 例: return listener.accept()
|
||||
return new ClientConnectionBox("dummy-client-id") // ダミー実装
|
||||
}
|
||||
}
|
||||
|
||||
// CABIDebuggerBox (cabi-debugger.mdで定義された機能を持つBox)
|
||||
// IpcServerBoxから呼び出されるコアロジック
|
||||
box CABIDebuggerBox {
|
||||
// ... 既存のフック、検証、記録機能 ...
|
||||
|
||||
// ログ購読者リスト (クライアントID -> ログ送信チャネル)
|
||||
// 実際には、ログレベルなどの購読設定も持つ
|
||||
logSubscribers: MapBox<String, ChannelBox>
|
||||
|
||||
birth() {
|
||||
me.logSubscribers = new MapBox()
|
||||
// ...
|
||||
}
|
||||
|
||||
// ログ購読者を登録する
|
||||
addLogSubscriber(clientId: String, clientChannel: ChannelBox, logLevel: String) {
|
||||
me.logSubscribers.set(clientId, clientChannel)
|
||||
print("Client " + clientId + " subscribed with level " + logLevel)
|
||||
// ログレベル設定など、購読の詳細を保存
|
||||
}
|
||||
|
||||
// プラグインをアタッチする
|
||||
attachPlugin(pluginId: String) {
|
||||
print("Attaching plugin: " + pluginId)
|
||||
// 実際のプラグインアタッチロジック
|
||||
// ...
|
||||
}
|
||||
|
||||
// ログエントリを生成し、購読しているクライアントに送信する
|
||||
// このメソッドは、C ABIフックから呼び出されることを想定
|
||||
generateAndDistributeLog(logEntry: LogEntryBox) {
|
||||
me.logSubscribers.forEach((clientId, channel) => {
|
||||
// クライアントの購読設定(ログレベルなど)に基づいてフィルタリング
|
||||
if me.shouldSendLogToClient(clientId, logEntry) {
|
||||
channel.send(logEntry)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 特定のクライアントID宛のログを取得する (forwardDebuggerLogsToClientから呼び出される)
|
||||
getLogEntryForClient(clientId: String) -> LogEntryBox {
|
||||
// このメソッドは、実際にはgenerateAndDistributeLogがチャネルに送ったログを
|
||||
// クライアントのforwardDebuggerLogsToClientルーチンが受け取る形になる
|
||||
// ここでは簡略化のためダミーを返す
|
||||
return new LogEntryBox("Dummy log for " + clientId)
|
||||
}
|
||||
|
||||
shouldSendLogToClient(clientId: String, logEntry: LogEntryBox) -> Bool {
|
||||
// ログレベルフィルタリングなどのロジック
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// ダミーのBox定義 (実際のIPC実装やログエントリの構造に合わせる)
|
||||
box ClientConnectionBox {
|
||||
id: String
|
||||
birth(id: String) { me.id = id }
|
||||
id() -> String { return me.id }
|
||||
receiveCommand() -> CommandBox { /* ダミー */ return new CommandBox("subscribe", "info") }
|
||||
sendResponse(id: String, response: Box) { /* ダミー */ }
|
||||
onClose(handler: Function) { /* ダミー */ }
|
||||
}
|
||||
|
||||
box CommandBox {
|
||||
method: String
|
||||
params: MapBox<String, Box>
|
||||
id: String
|
||||
birth(method: String, param: String) { me.method = method; me.params = new MapBox(); me.id = "1" }
|
||||
}
|
||||
|
||||
box OkBox { birth() {} }
|
||||
box ErrorBox { birth(msg: String) {} }
|
||||
box LogEntryBox { birth(msg: String) {} }
|
||||
@ -1,125 +0,0 @@
|
||||
# CAX発想プロセス記録 - 1分間の技術的洞察
|
||||
|
||||
**発想者**: nyash開発者
|
||||
**発想時刻**: 2025-09-21
|
||||
**所要時間**: 約1分
|
||||
**背景**: Mini-VM開発中、C ABI動的呼び出し議論から
|
||||
|
||||
## 🧠 発想の直線的プロセス
|
||||
|
||||
### Initial Context (0秒)
|
||||
```
|
||||
議題: 「C ABIを動的にプラグインのように取り外しも まあ できるかにゃ やる意味はおいといて」
|
||||
↓
|
||||
ChatGPT回答: 「技術的にはほぼYES」(dlopen/dlsym/安全ガード等の詳細分析)
|
||||
```
|
||||
|
||||
### Breakthrough Moment (約10秒)
|
||||
```
|
||||
発想: 「やるいみ おもいついたかもしれない きいてー」
|
||||
↓
|
||||
直感: 「うふふふふふふふ C ABI デバッガーーーーー!!!!」
|
||||
↓
|
||||
確信: 「もしかして 最強に 需要あるかもしれにゃい」
|
||||
```
|
||||
|
||||
### Technical Insight (約30秒)
|
||||
```
|
||||
技術的根拠の即座な理解:
|
||||
- C/CPython/ネイティブの「ABIバグ」が最厄介
|
||||
- 既存gdb/ASANは境界の意味論が見えない
|
||||
- Nyash箱理論 → 境界で完全トレース可能
|
||||
→ 「世界でも珍しいレベルのABIデバッグ体験」
|
||||
```
|
||||
|
||||
### UX Vision (約60秒)
|
||||
```
|
||||
直感的体験設計:
|
||||
「GUIで エクスプローラーみたいながめんから ぽいっと付けたり外したり
|
||||
ログもGUIで 入力もマクロなど自由自在」
|
||||
```
|
||||
|
||||
## 🌟 発想の技術的妥当性
|
||||
|
||||
### なぜ1分で到達できたか
|
||||
|
||||
#### 1. **技術基盤の理解**
|
||||
- Nyash箱理論: TypeBox/PluginHost境界の明確性
|
||||
- 既存ABI: C ABI呼び出し機構の理解
|
||||
- 問題認識: 境界バグの困難性を体感済み
|
||||
|
||||
#### 2. **直感的問題発見**
|
||||
```
|
||||
C ABI動的 → 「取り外し可能?」
|
||||
↓
|
||||
境界操作 → 「デバッグが困難」
|
||||
↓
|
||||
観測・制御 → 「専用ツールが必要」
|
||||
```
|
||||
|
||||
#### 3. **解決策の即座構築**
|
||||
```
|
||||
観測: ログ・トレース・可視化
|
||||
制御: アタッチ・デタッチ・ホットスワップ
|
||||
体験: GUI・自動化・直感的操作
|
||||
```
|
||||
|
||||
## 💡 発想の独創性分析
|
||||
|
||||
### 既存アプローチとの差別化
|
||||
```
|
||||
従来: gdb/ASAN = 汎用デバッガでABI境界は副次的
|
||||
CAX: ABI境界専用 = 境界観測に特化した設計
|
||||
```
|
||||
|
||||
### Nyash特有の優位性
|
||||
```
|
||||
箱理論: 境界が明確 → フック位置の自明性
|
||||
統一ライフサイクル: birth/fini → 所有権追跡容易
|
||||
型安全: TypeBox → 実時間型検証可能
|
||||
```
|
||||
|
||||
## 🎯 発想の実現可能性
|
||||
|
||||
### 技術的実現性(ChatGPT分析)
|
||||
- **Core実装**: 2週間MVP可能
|
||||
- **GUI実装**: Tauri/Electron + 既存IPC
|
||||
- **アーキテクチャ**: 既存基盤活用可能
|
||||
|
||||
### 市場性(直感的評価)
|
||||
- **開発者需要**: ABI境界バグは普遍的問題
|
||||
- **差別化**: 既存ツールにない専用機能
|
||||
- **Nyash優位**: 箱理論による技術的アドバンテージ
|
||||
|
||||
## 🚀 発想の発展性
|
||||
|
||||
### ChatGPT展開(30分)
|
||||
- 具体的UX設計
|
||||
- アーキテクチャ詳細化
|
||||
- 実装ロードマップ
|
||||
- リスク分析・対策
|
||||
|
||||
### Gemini実装(直後)
|
||||
- 172行実装コード
|
||||
- IPC層具体化
|
||||
- RoutineBox/ChannelBox活用
|
||||
- 即実装可能レベルまで具体化
|
||||
|
||||
## 📝 技術史的意義
|
||||
|
||||
### 個人開発+AI協働の威力
|
||||
```
|
||||
1分: 核心アイデア発見(人間)
|
||||
30分: 設計具体化(ChatGPT)
|
||||
直後: 実装コード(Gemini)
|
||||
→ 数時間で「世界初ツール」のプロトタイプ完成
|
||||
```
|
||||
|
||||
### 発想の本質
|
||||
- **直感性**: 技術制約から新可能性を即座発見
|
||||
- **実用性**: 実際の開発痛点からのソリューション
|
||||
- **革新性**: 既存アプローチの根本的再設計
|
||||
|
||||
---
|
||||
|
||||
**結論**: この1分間の発想は、技術的直感・問題発見力・解決策構築力の集約であり、AI協働開発の理想的パターンを実証した記録である。
|
||||
@ -1,186 +0,0 @@
|
||||
# CAX Technical Roadmap - Post‑Bootstrap Implementation Plan
|
||||
|
||||
**Target**: Mini-VM完成後の即実装
|
||||
**Duration**: 2-3週間でMVP完成
|
||||
**Dependency**: Mini-VM安定化 + 既存PluginHost基盤
|
||||
|
||||
## 🏗️ Implementation Phases
|
||||
|
||||
### Phase 0: Foundation (Mini-VM安定化待ち)
|
||||
**Duration**: Mini-VM完成まで
|
||||
**Tasks**:
|
||||
- ✅ 設計文書化(完了)
|
||||
- ✅ Gemini実装コード保存(完了)
|
||||
- ✅ ChatGPT設計仕様保存(完了)
|
||||
- [ ] 既存PluginHost.Invoke調査
|
||||
- [ ] IPC実装方式決定(WebSocket/Unix Socket)
|
||||
|
||||
### Phase 1: Core Implementation (Week 1)
|
||||
**Duration**: 5日間
|
||||
**Deliverables**: 基本IPC + 最小GUI
|
||||
|
||||
#### Backend (3日)
|
||||
```rust
|
||||
// src/tools/cax_server/
|
||||
├── ipc_server.rs // IPC通信層
|
||||
├── cabi_debugger.rs // フック・ログ・検証
|
||||
├── plugin_manager.rs // アタッチ・デタッチ管理
|
||||
└── main.rs // サーバー起動
|
||||
```
|
||||
|
||||
#### Frontend (2日)
|
||||
```typescript
|
||||
// gui/cax/
|
||||
├── src/
|
||||
│ ├── components/
|
||||
│ │ ├── Explorer.svelte // プラグイン一覧
|
||||
│ │ ├── Timeline.svelte // ライブログ表示
|
||||
│ │ └── Inspector.svelte // 詳細表示
|
||||
│ ├── api/
|
||||
│ │ └── cax_client.ts // IPC通信
|
||||
│ └── App.svelte // メインアプリ
|
||||
└── tauri.conf.json
|
||||
```
|
||||
|
||||
#### MVP機能
|
||||
- [x] プラグイン一覧表示
|
||||
- [x] アタッチ/デタッチボタン
|
||||
- [x] リアルタイムログ表示(JSONL)
|
||||
- [x] 基本フィルタリング
|
||||
|
||||
### Phase 2: Advanced Features (Week 2)
|
||||
**Duration**: 5日間
|
||||
**Deliverables**: Record/Replay + Hot-swap
|
||||
|
||||
#### Record/Replay System
|
||||
```rust
|
||||
// レコーダー
|
||||
pub struct CallRecorder {
|
||||
output: BufWriter<File>,
|
||||
format: RecordFormat, // JSONL | TLV
|
||||
}
|
||||
|
||||
// リプレイヤー
|
||||
pub struct CallReplayer {
|
||||
calls: Vec<RecordedCall>,
|
||||
mock_mode: bool, // プラグイン無しで再生
|
||||
}
|
||||
```
|
||||
|
||||
#### Hot-Swap Management
|
||||
```rust
|
||||
// ホットスワップ管理
|
||||
pub struct PluginSwapper {
|
||||
state: SwapState, // Attached | Quiescing | Swapping
|
||||
pending_calls: AtomicU64,
|
||||
swap_queue: VecDeque<SwapRequest>,
|
||||
}
|
||||
```
|
||||
|
||||
#### GUI拡張
|
||||
- [x] 録画/再生コントロール
|
||||
- [x] ホットスワップウィザード
|
||||
- [x] コール詳細インスペクター
|
||||
- [x] 簡易スクリプト実行
|
||||
|
||||
### Phase 3: Polish & Advanced (Week 3)
|
||||
**Duration**: 5日間
|
||||
**Deliverables**: 本格運用可能版
|
||||
|
||||
#### Analytics & Visualization
|
||||
```typescript
|
||||
// ヒートマップ・統計表示
|
||||
interface CallStats {
|
||||
plugin: string
|
||||
method: string
|
||||
call_count: number
|
||||
avg_time_us: number
|
||||
error_rate: number
|
||||
hot_paths: string[]
|
||||
}
|
||||
```
|
||||
|
||||
#### Advanced Scripting
|
||||
```nyash
|
||||
// CAX Macro API
|
||||
using cax.api as CAX
|
||||
|
||||
CAX.enable({profile: true, assert: "warn"})
|
||||
CAX.attach("map.so")
|
||||
|
||||
// 自動化スクリプト例
|
||||
local errorCount = CAX.filter({outcome: "error"}).count()
|
||||
if errorCount > 10 {
|
||||
CAX.hotswap("map.so", "/backup/map_stable.so")
|
||||
}
|
||||
```
|
||||
|
||||
#### Production Features
|
||||
- [x] 詳細設定・永続化
|
||||
- [x] エクスポート(HTML/PDF レポート)
|
||||
- [x] プラグイン署名検証
|
||||
- [x] 権限・セキュリティ管理
|
||||
|
||||
## 🎯 Success Criteria
|
||||
|
||||
### MVP Success (Phase 1)
|
||||
- [x] プラグインアタッチ→ログ表示まで1クリック
|
||||
- [x] リアルタイム表示でパフォーマンス影響<5%
|
||||
- [x] 基本的なABIバグ(型ミスマッチ)を検出
|
||||
|
||||
### Advanced Success (Phase 2)
|
||||
- [x] Record→Replay でCI回帰テスト実現
|
||||
- [x] ホットスワップでサービス無停止更新
|
||||
- [x] 複雑なABIバグを根本特定
|
||||
|
||||
### Production Success (Phase 3)
|
||||
- [x] 日常開発ワークフローに統合
|
||||
- [x] 他言語(Python/C++)開発者も使用開始
|
||||
- [x] 学術発表・OSS公開で注目獲得
|
||||
|
||||
## 🔧 Technical Implementation Notes
|
||||
|
||||
### IPC選択基準
|
||||
```
|
||||
WebSocket: ブラウザベースGUI用(開発容易)
|
||||
Unix Socket: ネイティブGUI用(性能優先)
|
||||
→ 両対応、設定で選択可能
|
||||
```
|
||||
|
||||
### フック実装位置
|
||||
```rust
|
||||
// PluginHost::invoke の入口・出口
|
||||
impl PluginHost {
|
||||
pub fn invoke(&self, call: &PluginCall) -> Result<Value> {
|
||||
CAX_TRACER.pre_call(call); // 🎯 フック点1
|
||||
let result = self.invoke_impl(call);
|
||||
CAX_TRACER.post_call(call, &result); // 🎯 フック点2
|
||||
result
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### パフォーマンス最適化
|
||||
```rust
|
||||
// 条件付きトレース(オーバーヘッド最小化)
|
||||
if CAX_ENABLED.load(Ordering::Relaxed) {
|
||||
tracer.log_call(call_info);
|
||||
}
|
||||
|
||||
// 非同期ログ書き込み
|
||||
async fn log_writer(mut receiver: Receiver<LogEntry>) {
|
||||
while let Some(entry) = receiver.recv().await {
|
||||
// バッファリング→バッチ書き込み
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📅 Realistic Timeline
|
||||
|
||||
**Prerequisite**: Mini-VM安定化(推定2-3週間)
|
||||
**Implementation**: CAX開発(3週間)
|
||||
**Total**: 約6週間でプロダクション品質版完成
|
||||
|
||||
---
|
||||
|
||||
**Note**: この実装計画は、Geminiの172行実装とChatGPTの設計仕様を基に、現実的なタイムラインで作成。Mini-VM完成後、即座に実装開始可能。
|
||||
@ -1,123 +0,0 @@
|
||||
# Instance v2 統一レジストリ設計メモ(提案)
|
||||
|
||||
目的: ユーザー定義 / ビルトイン / プラグインの3系統を instance_v2 で一元管理し、同一の生成(birth)/破棄(fini)ライフサイクルで扱えるようにする。また、wasm-bindgen ターゲットでプラグイン機構を安全に無効化できる切替を用意する。
|
||||
|
||||
---
|
||||
|
||||
## 現状の整理(実装済み)
|
||||
- ユーザー定義Box
|
||||
- インタプリタの AST → InstanceBox 生成で対応済み。
|
||||
- `execute_new` は最初に統一レジストリを呼び、ユーザー定義については最終的に `InstanceBox` を構築し、birth 相当のコンストラクタ実行を行う。
|
||||
- ビルトインBox
|
||||
- 統一レジストリ経由で生成可能。ユーザー定義と同じ呼び出し経路に乗る。
|
||||
- プラグインBox(v2)
|
||||
- `nyash.toml v2` を `PluginLoaderV2` が読み込み、`nyash_plugin_invoke` の birth 呼び出しでインスタンスを生成。
|
||||
- 現状、`PluginBoxV2` は `clone_box=新birth`、`share_box=同一 instance_id` を実装済み。
|
||||
|
||||
---
|
||||
|
||||
## 目標
|
||||
1. 3系統(ユーザー定義/ビルトイン/プラグイン)を「統一レジストリ→instance_v2」で一元管理。
|
||||
2. birth/fini ライフサイクルの整合をとる。
|
||||
3. wasm-bindgen ターゲット(`wasm32-unknown-unknown`)ではプラグイン機構をコンパイル時に無効化し、ビルド可能にする。
|
||||
|
||||
---
|
||||
|
||||
## 設計方針
|
||||
|
||||
### 1) 統一レジストリの責務
|
||||
- 名前(クラス名)と引数(`Box<dyn NyashBox>` の配列)を入力に、ユーザー定義/ビルトイン/プラグインの順で解決・生成を試みる。
|
||||
- 生成に成功したら `Box<dyn NyashBox>` を返す。
|
||||
- ユーザー定義: `InstanceBox` とし、インタプリタがコンストラクタ(birth)を実行。
|
||||
- ビルトイン: 直接生成(必要なら簡易birth相当の初期化)
|
||||
- プラグイン: `PluginLoaderV2` の `invoke_fn(type_id, method_id=0=birth, ...)` を呼ぶ。
|
||||
|
||||
### 2) birth / fini ライフサイクル
|
||||
- birth:
|
||||
- ユーザー定義: 既存通り AST 上のコンストラクタ(birth)を呼ぶ。
|
||||
- プラグイン: `nyash.toml` の `methods.birth` の method_id=0 を使い、`invoke_fn` 呼び出しで instance_id を取得済み。
|
||||
- fini:
|
||||
- InstanceBox のフィールド差し替え時、旧値が InstanceBox なら `fini()` を呼んで finalize 済みIDとしてマーキング(実装済み)。
|
||||
- プラグインBoxについても `nyash.toml` で `methods.fini`(例: 0xFFFF)を定義し、差し替えやスコープ終端で `invoke_fn(type_id, method_id=fini, instance_id, ...)` を呼ぶ。エラーは握りつぶさずログ化。
|
||||
|
||||
### 3) wasm-bindgen ターゲットでの切り替え
|
||||
- Cargo features によるコンパイル時ガードを導入:
|
||||
- `plugins`(デフォルトON)、`wasm-backend`(WASMビルド用)の2フラグを用意。
|
||||
- `#[cfg(all(feature = "plugins", not(target_arch = "wasm32")))]` のときのみ `plugin_loader_v2` 実体を有効化。
|
||||
- それ以外では `plugin_loader_v2` のスタブ実装を使う(常に `Err(BidError::PluginError)` を返すなど)。
|
||||
- 統一レジストリはプラグインFactoryの登録を `#[cfg(feature="plugins")]` でガードし、WASMビルドでもユーザー定義/ビルトインは動かせる。
|
||||
- `nyash.toml` のファイルI/O(`from_file`)も `cfg` で握り、WASMではロードしない。
|
||||
|
||||
---
|
||||
|
||||
## nyash.toml v2 との整合
|
||||
- 既存:
|
||||
- `libraries.<libname>.boxes = ["FileBox"]`
|
||||
- `libraries.<libname>.<BoxType>.methods.birth = { method_id = 0 }`
|
||||
- `... .fini = { method_id = 4294967295 }` など
|
||||
- 追加検討:
|
||||
- 将来、ユーザー定義Boxをプラグインで置換したい場合:
|
||||
- クラス名→プラグインBox型の上書きマップを `nyash.toml` に追加(例:`overrides = { "DataBox" = "libX::RemoteDataBox" }`)。
|
||||
- 統一レジストリがこのマップを見て、ユーザー定義をスキップしてプラグインへ委譲。
|
||||
|
||||
---
|
||||
|
||||
## API/コード上の具体案(抜粋)
|
||||
- features(`Cargo.toml`):
|
||||
```toml
|
||||
[features]
|
||||
default = ["plugins"]
|
||||
plugins = []
|
||||
wasm-backend = []
|
||||
```
|
||||
- プラグインローダ(`src/runtime/plugin_loader_v2.rs`):
|
||||
```rust
|
||||
#[cfg(all(feature = "plugins", not(target_arch = "wasm32")))]
|
||||
pub mod real_loader { /* 現在の実装 */ }
|
||||
|
||||
#[cfg(any(not(feature = "plugins"), target_arch = "wasm32"))]
|
||||
pub mod stub_loader {
|
||||
use crate::bid::{BidResult, BidError};
|
||||
use crate::box_trait::NyashBox;
|
||||
pub struct PluginLoaderV2; // ダミー
|
||||
impl PluginLoaderV2 { pub fn new() -> Self { Self } }
|
||||
impl PluginLoaderV2 {
|
||||
pub fn load_config(&mut self, _p: &str) -> BidResult<()> { Ok(()) }
|
||||
pub fn load_all_plugins(&self) -> BidResult<()> { Ok(()) }
|
||||
pub fn create_box(&self, _t: &str, _a: &[Box<dyn NyashBox>]) -> BidResult<Box<dyn NyashBox>> {
|
||||
Err(BidError::PluginError)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
- 統一レジストリのFactory登録部は `#[cfg(feature = "plugins")]` でプラグインFactoryの登録を条件化。
|
||||
|
||||
---
|
||||
|
||||
## マイグレーション手順(段階)
|
||||
1. Cargo features と cfg ガードの導入(プラグイン機構のスタブ化を含む)。
|
||||
2. 統一レジストリのプラグインFactory登録の条件化。
|
||||
3. プラグインBoxの `fini` 呼び出し用メソッドを InstanceBox 置換/破棄パスへ組み込む。
|
||||
4. 必要に応じて `nyash.toml` の `methods.fini` を明記。
|
||||
5. 追加要件(ユーザー定義のプラグイン置換)を `overrides` マップで設計 → 実装。
|
||||
|
||||
---
|
||||
|
||||
## テスト観点
|
||||
- ユニット:
|
||||
- birth/fini の呼び出し順と複数回置換時の `fini` 呼び出し保証。
|
||||
- `plugins` ON/OFF、`wasm-backend` ON の3軸でビルド/テストが通ること。
|
||||
- 統合テスト:
|
||||
- `nyash.toml` によるビルトイン→プラグインの透過切替。
|
||||
- ユーザー定義→ビルトイン→プラグインの優先順位が想定通り。
|
||||
|
||||
---
|
||||
|
||||
## メモ
|
||||
- すでに `execute_new` は統一レジストリ優先の実装になっており、この設計と整合が良い。
|
||||
- WASM ターゲットでは `libloading` が使えないため、コンパイル時に完全にプラグインコードを外す方針(cfg/feature)は自然。
|
||||
- `nyash.toml` のロードはネイティブ時のみで十分(WASM は将来、バンドルまたは JS 側から供給する計画があるなら別途)。
|
||||
|
||||
---
|
||||
|
||||
以上。必要であれば、この方針でPRを小さく分割(features→レジストリ→fini→overrides)して入れていきます。
|
||||
@ -1,80 +0,0 @@
|
||||
# Issue 62 Update Proposal: Enable String Constants in WASM Backend First
|
||||
|
||||
This is a concrete request to implement minimal string support in the WASM backend so that Issue #62 can proceed. It reflects the current repo state.
|
||||
|
||||
## Background
|
||||
|
||||
- As noted in Issue #61, the current WASM backend does not support string constants yet.
|
||||
- Issue #62 depends on string support and cannot be completed without it.
|
||||
- Current state:
|
||||
- `src/backend/wasm/codegen.rs` → `generate_const` handles only Integer/Bool/Void; String is not implemented.
|
||||
- `src/backend/wasm/memory.rs` already defines a basic layout for `StringBox`:
|
||||
- Header: `[type_id:i32][ref_count:i32][field_count:i32]`
|
||||
- Fields: `[data_ptr:i32][length:i32]`
|
||||
- `StringBox` type_id = `0x1001`.
|
||||
|
||||
## Goal
|
||||
|
||||
Add minimal string constant support to the WASM backend:
|
||||
|
||||
- Allow `ConstValue::String` in codegen by embedding UTF-8 string bytes and constructing a `StringBox` with `[data_ptr,length]`.
|
||||
- Provide a minimal debugging import `env.print_str(ptr,len)` to verify strings at runtime.
|
||||
- Unblock Issue #62 implementation and tests that require strings.
|
||||
|
||||
## Scope
|
||||
|
||||
Minimal features required:
|
||||
|
||||
1) Data segments for string literals
|
||||
- Extend `WasmModule` (in `codegen.rs`) with a `data_segments: Vec<String>` field.
|
||||
- Update `to_wat()` to emit `(data ...)` after memory/globals and before functions/exports.
|
||||
- For each string constant, create a unique offset and emit a `(data (i32.const <offset>) "...bytes...")` entry.
|
||||
|
||||
2) Codegen for `ConstValue::String`
|
||||
- In `generate_const`, when encountering `ConstValue::String(s)`,
|
||||
- Allocate a data segment for `s` (UTF-8 bytes) and get its offset and length.
|
||||
- Allocate a `StringBox` using existing helpers (see `MemoryManager`),
|
||||
then set its fields: `data_ptr` and `length`.
|
||||
- Return the `StringBox` pointer (i32) in the destination local.
|
||||
|
||||
3) Helper for `StringBox` allocation
|
||||
- Either:
|
||||
- Provide a dedicated WAT helper function `$alloc_stringbox` that calls `$malloc`, writes header (`type_id=0x1001`, `ref_count=1`, `field_count=2`), and returns the box pointer, then inline store `data_ptr`/`length`.
|
||||
- Or:
|
||||
- Use `$box_alloc` with `(type_id=0x1001, field_count=2)` and then store `data_ptr`/`length` via generated `i32.store` sequences.
|
||||
|
||||
4) Runtime import for string output (for verification)
|
||||
- Extend `RuntimeImports` (`src/backend/wasm/runtime.rs`) with:
|
||||
- `(import "env" "print_str" (func $print_str (param i32 i32)))`
|
||||
- In host (Node/Browser), implement `importObject.env.print_str = (ptr,len) => { decode UTF-8 from memory; console.log(...) }`.
|
||||
|
||||
5) E2E test
|
||||
- Add a tiny program that produces/prints a string (e.g., Const String → call `env.print_str(ptr,len)` via a minimal MIR program) and verify it logs the correct text.
|
||||
- Option: update `test_runner.js` to include `print_str` and decode from memory using `TextDecoder('utf-8')`.
|
||||
|
||||
## Out of Scope (for this change)
|
||||
|
||||
- String operations (concat/substr/compare), normalization, encoding conversions.
|
||||
- GC/RC or freeing memory (current allocator is bump-only).
|
||||
- Returning StringBox directly from `main` (keep verification via `print_str`).
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- Generated WAT includes `(data ...)` segments for string literals and correct offsets.
|
||||
- `ConstValue::String` codegen constructs a valid `StringBox` with proper `[data_ptr,length]`.
|
||||
- `env.print_str` correctly prints UTF-8 strings in both Browser and Node runners.
|
||||
- Issue #62 tasks that rely on strings can proceed.
|
||||
|
||||
## References (repo paths)
|
||||
|
||||
- String unsupported path: `src/backend/wasm/codegen.rs` (`generate_const`)
|
||||
- Memory/layout: `src/backend/wasm/memory.rs` (StringBox, type_id=0x1001)
|
||||
- Runtime imports: `src/backend/wasm/runtime.rs` (currently only `env.print(i32)`)
|
||||
- Node runner: `test_runner.js` (has `env.print`; extend with `print_str`)
|
||||
|
||||
## Notes
|
||||
|
||||
- Data segment approach is the simplest for initial support; future work may add constant pooling and deduplication.
|
||||
- Keeping verification via `print_str(ptr,len)` avoids complicating function return types for now.
|
||||
- UTF-8 decoding is available in hosts via `TextDecoder('utf-8')`.
|
||||
|
||||
@ -1,84 +0,0 @@
|
||||
# PoC Plan: TypeOp / WeakRef / Barrier Unification
|
||||
|
||||
Status: Draft (PoC design)
|
||||
Last Updated: 2025-08-23
|
||||
|
||||
## Goals
|
||||
- Reduce instruction surface without losing expressiveness or performance.
|
||||
- Provide a feature-gated PoC to validate that consolidation is safe and measurable.
|
||||
|
||||
## Scope
|
||||
- Unify TypeCheck + Cast → TypeOp (single instruction)
|
||||
- Unify WeakNew + WeakLoad → WeakRef (single instruction)
|
||||
- Unify BarrierRead + BarrierWrite → Barrier (single instruction)
|
||||
|
||||
## Out of Scope (PoC)
|
||||
- Remap language syntax or external APIs
|
||||
- Remove legacy instructions permanently (kept behind feature flags)
|
||||
|
||||
## Feature Flags (Cargo)
|
||||
Note: 2025-08 Phase 9.78h 時点で統合命令はデフォルトとなり、以下のflagsは非推奨(no-op)だよ:
|
||||
|
||||
- `mir_typeop_poc`: Builderは常に`TypeOp(Check/Cast)`を生成(旧`TypeCheck/Cast`は使わない)。
|
||||
- `mir_refbarrier_unify_poc`: Builderは常に`WeakRef/Barrier`を生成(旧`WeakNew/WeakLoad/BarrierRead/Write`は使わない)。
|
||||
|
||||
互換性のため、Optimizerに旧命令→統合命令への正規化パス(Pass 0)が入っているにゃ。
|
||||
|
||||
## Mapping (Current → PoC)
|
||||
- TypeCheck { value, expected_type } → TypeOp { op: Check, value, type } (bool)
|
||||
- Cast { value, target_type } → TypeOp { op: Cast, value, type } (value)
|
||||
- WeakNew { dst, box_val } → WeakRef { op: New, dst, box_val }
|
||||
- WeakLoad { dst, weak_ref } → WeakRef { op: Load, dst, weak_ref }
|
||||
- BarrierRead { ptr } → Barrier { op: Read, ptr }
|
||||
- BarrierWrite { ptr } → Barrier { op: Write, ptr }
|
||||
|
||||
## Implementation Steps
|
||||
1) MIR instruction additions
|
||||
- Add TypeOp/WeakRef/Barrier enums with minimal payloads
|
||||
- Keep legacy instructions compiled-in (no behavior change yet)
|
||||
2) Builder mapping (feature-gated)
|
||||
- Under flags, emit unified instructions instead of legacy
|
||||
3) VM execution mapping
|
||||
- Implement execute paths for TypeOp/WeakRef/Barrier
|
||||
- Legacy paths continue to work for fallback
|
||||
4) Printer/Stats
|
||||
- Name new ops distinctly; ensure stats collection reflects consolidated ops
|
||||
5) Tests
|
||||
- Snapshot tests for builder mapping (with/without flags)
|
||||
- VM exec parity tests for legacy vs unified
|
||||
|
||||
## Rollout / Migration
|
||||
- Phase A (PoC): flags off by default, CI job with flags on
|
||||
- Phase B (Dual): flags on by default in dev; legacy paths still supported
|
||||
- Phase C (Switch): remove legacy or keep as aliases (no-emit) depending on impact
|
||||
|
||||
## Impact Areas
|
||||
- `src/mir/instruction.rs` (add new ops; Display/used_values/dst_value)
|
||||
- `src/mir/builder.rs` (conditional emit)
|
||||
- `src/backend/vm.rs` (execution paths + stats key)
|
||||
- `src/mir/printer.rs` (print new ops)
|
||||
- Tests: MIR/VM/E2E minimal parity checks
|
||||
|
||||
## Acceptance Criteria
|
||||
- All current tests pass with flags off (default)
|
||||
- With flags on:
|
||||
- Unit/snapshot tests pass
|
||||
- vm-stats shows expected consolidation (TypeOp/WeakRef/Barrier vs legacy)
|
||||
- No regressions in FileBox/Net E2E under plugins
|
||||
|
||||
## Metrics to Watch
|
||||
- vm-stats: proportion of TypeOp/WeakRef/Barrier vs legacy in representative scenarios
|
||||
- Build time impact: negligible
|
||||
- Code size: small reduction after removal
|
||||
|
||||
## Risks / Mitigations
|
||||
- Risk: Unified ops obscure dataflow for some analyses
|
||||
- Mitigation: Verifier hooks to introspect TypeOp semantics; keep legacy printer names during PoC
|
||||
- Risk: Plugins or external tooling tied to legacy names
|
||||
- Mitigation: MIR remains internal; external ABI unaffected
|
||||
|
||||
## Next Steps
|
||||
- Land scaffolding (no behavior change)
|
||||
- Add builder mapping behind flags
|
||||
- Add VM execution behind flags
|
||||
- Gate CI job to run PoC flags on Linux
|
||||
@ -1,362 +0,0 @@
|
||||
# MIR 35→26→15命令削減: 詳細分析・移行戦略
|
||||
|
||||
*実装ベース完全マッピング - 2025年8月17日版*
|
||||
**注意**: このドキュメントは35→26命令への移行計画を記録しています。現在はさらに15命令に削減済みです。
|
||||
|
||||
## 🔍 **過去の実装35命令 vs 26命令仕様の完全マッピング(歴史的記録)**
|
||||
|
||||
### **維持する命令 (35命令実装 → 26命令仕様への移行計画)**
|
||||
|
||||
| 現在実装 | 26命令仕様 | 効果 | 変更 |
|
||||
|----------|------------|------|------|
|
||||
| `Const` | `Const` | pure | ✅ 維持 |
|
||||
| `BinOp` | `BinOp` | pure | ✅ 維持 |
|
||||
| `Compare` | `Compare` | pure | ✅ 維持 |
|
||||
| `Branch` | `Branch` | control | ✅ 維持 |
|
||||
| `Jump` | `Jump` | control | ✅ 維持 |
|
||||
| `Phi` | `Phi` | pure | ✅ 維持 |
|
||||
| `Call` | `Call` | context | ✅ 維持 |
|
||||
| `Return` | `Return` | control | ✅ 維持 |
|
||||
| `NewBox` | `NewBox` | mut | ✅ 維持 |
|
||||
| `BoxCall` | `BoxCall` | context | ✅ 維持 |
|
||||
| `ExternCall` | `ExternCall` | context | ✅ 維持 |
|
||||
| `Safepoint` | `Safepoint` | io | ✅ 維持 |
|
||||
| `RefGet` | `RefGet` | pure | ✅ 維持 |
|
||||
| `RefSet` | `RefSet` | mut | ✅ 維持 |
|
||||
| `WeakNew` | `WeakNew` | pure | ✅ 維持 |
|
||||
| `WeakLoad` | `WeakLoad` | pure | ✅ 維持 |
|
||||
|
||||
**小計**: 16命令維持
|
||||
|
||||
### **削除する命令 (17命令)**
|
||||
|
||||
#### **グループ1: BinOp統合 (1命令)**
|
||||
|
||||
| 削除命令 | 置換方法 | 実装例 |
|
||||
|----------|----------|--------|
|
||||
| `UnaryOp` | `BinOp`統合 | `not %a` → `%a xor true`<br>`neg %a` → `0 sub %a` |
|
||||
|
||||
#### **グループ2: BoxField操作統合 (4命令)**
|
||||
|
||||
| 削除命令 | 置換方法 | 実装例 |
|
||||
|----------|----------|--------|
|
||||
| `Load` | `BoxFieldLoad` | `load %ptr` → `%ptr.value` |
|
||||
| `Store` | `BoxFieldStore` | `store %val -> %ptr` → `%ptr.value = %val` |
|
||||
| `ArrayGet` | `BoxFieldLoad` | `%arr[%idx]` → `%arr.elements[%idx]` |
|
||||
| `ArraySet` | `BoxFieldStore` | `%arr[%idx] = %val` → `%arr.elements[%idx] = %val` |
|
||||
|
||||
#### **グループ3: intrinsic化 (6命令)**
|
||||
|
||||
| 削除命令 | intrinsic名 | 実装例 |
|
||||
|----------|-------------|--------|
|
||||
| `Print` | `@print` | `print %val` → `call @print, %val` |
|
||||
| `Debug` | `@debug` | `debug %val "msg"` → `call @debug, %val, "msg"` |
|
||||
| `TypeCheck` | `@type_check` | `type_check %val "Type"` → `call @type_check, %val, "Type"` |
|
||||
| `Cast` | `@cast` | `cast %val Type` → `call @cast, %val, Type` |
|
||||
| `Throw` | `@throw` | `throw %exc` → `call @throw, %exc` |
|
||||
| `Catch` | `@catch` | `catch Type -> %bb` → `call @catch, Type, %bb` |
|
||||
|
||||
#### **グループ4: 完全削除 (3命令)**
|
||||
|
||||
| 削除命令 | 削除理由 | 代替方法 |
|
||||
|----------|----------|----------|
|
||||
| `Copy` | 最適化パス専用 | 最適化段階でのみ使用 |
|
||||
| `Nop` | 不要 | 削除(プレースホルダー不要) |
|
||||
| `RefNew` | 冗長 | `RefGet`で代用可能 |
|
||||
|
||||
#### **グループ5: 統合・置換 (3命令)**
|
||||
|
||||
| 削除命令 | 統合先 | 実装例 |
|
||||
|----------|--------|--------|
|
||||
| `BarrierRead` | `AtomicFence` | `barrier_read %ptr` → `atomic_fence acquire` |
|
||||
| `BarrierWrite` | `AtomicFence` | `barrier_write %ptr` → `atomic_fence release` |
|
||||
| `FutureNew` | `NewBox + BoxCall` | `future_new %val` → `%f = new_box "Future"(%val)` |
|
||||
| `FutureSet` | `BoxCall` | `future_set %f = %val` → `%f.set(%val)` |
|
||||
| `Await` | `BoxCall` | `await %f` → `%f.await()` |
|
||||
|
||||
### **追加する命令 (10命令)**
|
||||
|
||||
| 新命令 | 効果 | 目的 | 実装必要度 |
|
||||
|--------|------|------|------------|
|
||||
| `BoxFieldLoad` | pure | Everything is Box核心 | 🔥 Critical |
|
||||
| `BoxFieldStore` | mut | Everything is Box核心 | 🔥 Critical |
|
||||
| `WeakCheck` | pure | weak参照完全対応 | ⚡ High |
|
||||
| `Send` | io | Bus操作一次市民化 | ⚡ High |
|
||||
| `Recv` | io | Bus操作一次市民化 | ⚡ High |
|
||||
| `TailCall` | control | JIT最適化基盤 | 📝 Medium |
|
||||
| `Adopt` | mut | 所有権移管明示 | 📝 Medium |
|
||||
| `Release` | mut | 所有権移管明示 | 📝 Medium |
|
||||
| `MemCopy` | mut | 最適化基盤 | 📝 Medium |
|
||||
| `AtomicFence` | io | 並行制御統一 | 📝 Medium |
|
||||
|
||||
## 🛠️ **具体的実装戦略**
|
||||
|
||||
### **Phase 1: 新命令実装**
|
||||
|
||||
#### **BoxFieldLoad/BoxFieldStore実装**
|
||||
```rust
|
||||
// src/mir/instruction.rs
|
||||
pub enum MirInstruction {
|
||||
// 新規追加
|
||||
BoxFieldLoad {
|
||||
dst: ValueId,
|
||||
box_val: ValueId,
|
||||
field: String,
|
||||
},
|
||||
BoxFieldStore {
|
||||
box_val: ValueId,
|
||||
field: String,
|
||||
value: ValueId,
|
||||
},
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### **WeakCheck実装**
|
||||
```rust
|
||||
WeakCheck {
|
||||
dst: ValueId,
|
||||
weak_ref: ValueId,
|
||||
}
|
||||
```
|
||||
|
||||
#### **Send/Recv実装**
|
||||
```rust
|
||||
Send {
|
||||
data: ValueId,
|
||||
target: ValueId,
|
||||
},
|
||||
Recv {
|
||||
dst: ValueId,
|
||||
source: ValueId,
|
||||
},
|
||||
```
|
||||
|
||||
### **Phase 2: intrinsic関数システム実装**
|
||||
|
||||
#### **intrinsic レジストリ**
|
||||
```rust
|
||||
// src/interpreter/intrinsics.rs
|
||||
pub struct IntrinsicRegistry {
|
||||
functions: HashMap<String, IntrinsicFunction>,
|
||||
}
|
||||
|
||||
impl IntrinsicRegistry {
|
||||
pub fn new() -> Self {
|
||||
let mut registry = Self { functions: HashMap::new() };
|
||||
registry.register("@print", intrinsic_print);
|
||||
registry.register("@debug", intrinsic_debug);
|
||||
registry.register("@type_check", intrinsic_type_check);
|
||||
registry.register("@cast", intrinsic_cast);
|
||||
registry.register("@array_get", intrinsic_array_get);
|
||||
registry.register("@array_set", intrinsic_array_set);
|
||||
registry
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **intrinsic関数実装例**
|
||||
```rust
|
||||
fn intrinsic_print(args: &[Value]) -> Result<Value, RuntimeError> {
|
||||
println!("{}", args[0]);
|
||||
Ok(Value::Void)
|
||||
}
|
||||
|
||||
fn intrinsic_array_get(args: &[Value]) -> Result<Value, RuntimeError> {
|
||||
let array = args[0].as_array_box()?;
|
||||
let index = args[1].as_integer()?;
|
||||
array.get_element(index as usize)
|
||||
}
|
||||
|
||||
fn intrinsic_array_set(args: &[Value]) -> Result<Value, RuntimeError> {
|
||||
let array = args[0].as_array_box_mut()?;
|
||||
let index = args[1].as_integer()?;
|
||||
let value = args[2].clone();
|
||||
array.set_element(index as usize, value)
|
||||
}
|
||||
```
|
||||
|
||||
### **Phase 3: AST→MIR生成更新**
|
||||
|
||||
#### **Load/Store → BoxFieldLoad/BoxFieldStore変換**
|
||||
```rust
|
||||
// src/mir/builder.rs
|
||||
impl MirBuilder {
|
||||
fn visit_field_access(&mut self, node: &FieldAccessNode) -> Result<ValueId, BuildError> {
|
||||
let box_val = self.visit_expression(&node.object)?;
|
||||
let dst = self.new_temp_var();
|
||||
|
||||
// 旧: Load命令生成
|
||||
// self.emit(MirInstruction::Load { dst, ptr: box_val });
|
||||
|
||||
// 新: BoxFieldLoad命令生成
|
||||
self.emit(MirInstruction::BoxFieldLoad {
|
||||
dst,
|
||||
box_val,
|
||||
field: node.field.clone(),
|
||||
});
|
||||
|
||||
Ok(dst)
|
||||
}
|
||||
|
||||
fn visit_field_assignment(&mut self, node: &FieldAssignmentNode) -> Result<(), BuildError> {
|
||||
let box_val = self.visit_expression(&node.object)?;
|
||||
let value = self.visit_expression(&node.value)?;
|
||||
|
||||
// 旧: Store命令生成
|
||||
// self.emit(MirInstruction::Store { value, ptr: box_val });
|
||||
|
||||
// 新: BoxFieldStore命令生成
|
||||
self.emit(MirInstruction::BoxFieldStore {
|
||||
box_val,
|
||||
field: node.field.clone(),
|
||||
value,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **配列操作 → BoxField + intrinsic変換**
|
||||
```rust
|
||||
fn visit_array_access(&mut self, node: &ArrayAccessNode) -> Result<ValueId, BuildError> {
|
||||
let array = self.visit_expression(&node.array)?;
|
||||
let index = self.visit_expression(&node.index)?;
|
||||
let dst = self.new_temp_var();
|
||||
|
||||
// intrinsic化
|
||||
self.emit(MirInstruction::Call {
|
||||
dst: Some(dst),
|
||||
func: self.get_intrinsic_id("@array_get"),
|
||||
args: vec![array, index],
|
||||
effects: EffectMask::PURE,
|
||||
});
|
||||
|
||||
Ok(dst)
|
||||
}
|
||||
```
|
||||
|
||||
### **Phase 4: バックエンド対応**
|
||||
|
||||
#### **Interpreter実装**
|
||||
```rust
|
||||
// src/backend/interpreter.rs
|
||||
impl Interpreter {
|
||||
fn execute_box_field_load(&mut self, dst: ValueId, box_val: ValueId, field: &str) -> Result<(), RuntimeError> {
|
||||
let box_obj = self.get_value(box_val)?;
|
||||
let field_value = box_obj.get_field(field)?;
|
||||
self.set_value(dst, field_value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_box_field_store(&mut self, box_val: ValueId, field: &str, value: ValueId) -> Result<(), RuntimeError> {
|
||||
let mut box_obj = self.get_value_mut(box_val)?;
|
||||
let field_value = self.get_value(value)?;
|
||||
box_obj.set_field(field, field_value)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **VM実装**
|
||||
```rust
|
||||
// src/backend/vm.rs
|
||||
impl VM {
|
||||
fn exec_box_field_load(&mut self, dst: RegId, box_val: RegId, field_id: FieldId) -> VMResult<()> {
|
||||
let box_ptr = self.registers[box_val as usize];
|
||||
let field_value = unsafe {
|
||||
self.load_field(box_ptr, field_id)
|
||||
};
|
||||
self.registers[dst as usize] = field_value;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **WASM実装**
|
||||
```rust
|
||||
// src/backend/wasm/codegen.rs
|
||||
impl WasmCodegen {
|
||||
fn generate_box_field_load(&mut self, dst: ValueId, box_val: ValueId, field: &str) -> Result<(), CodegenError> {
|
||||
let box_addr = self.get_value_address(box_val)?;
|
||||
let field_offset = self.get_field_offset(field)?;
|
||||
|
||||
// WASM: i32.load offset=field_offset
|
||||
self.emit_wasm(&format!("i32.load offset={}", field_offset));
|
||||
self.set_value_register(dst);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 **移行スケジュール詳細**
|
||||
|
||||
### **Week 1: 基盤実装 (8/18-8/24)**
|
||||
- [ ] 新命令構造体定義
|
||||
- [ ] intrinsicレジストリ実装
|
||||
- [ ] パーサー拡張(新旧両対応)
|
||||
|
||||
### **Week 2: フロントエンド移行 (8/25-8/31)**
|
||||
- [ ] AST→MIR変換更新
|
||||
- [ ] 配列操作intrinsic化
|
||||
- [ ] Load/Store→BoxField変換
|
||||
|
||||
### **Week 3: 最適化パス移行 (9/1-9/7)**
|
||||
- [ ] Effect分類実装
|
||||
- [ ] 所有権森検証
|
||||
- [ ] BoxFieldLoad/Store最適化
|
||||
|
||||
### **Week 4: バックエンド移行 (9/8-9/14)**
|
||||
- [ ] Interpreter新命令実装
|
||||
- [ ] VM新命令実装
|
||||
- [ ] WASM新命令実装
|
||||
|
||||
### **Week 5: クリーンアップ (9/15-9/21)**
|
||||
- [ ] 旧命令完全削除
|
||||
- [ ] テスト更新
|
||||
- [ ] ドキュメント整備
|
||||
|
||||
## 🧪 **テスト・検証計画**
|
||||
|
||||
### **段階的テスト**
|
||||
```bash
|
||||
# Week 1終了時
|
||||
./scripts/test_mir_parsing_26.sh
|
||||
|
||||
# Week 2終了時
|
||||
./scripts/test_frontend_migration.sh
|
||||
|
||||
# Week 3終了時
|
||||
./scripts/test_optimization_passes.sh
|
||||
|
||||
# Week 4終了時
|
||||
./scripts/test_all_backends.sh
|
||||
|
||||
# Week 5終了時
|
||||
./scripts/test_golden_mir_final.sh
|
||||
```
|
||||
|
||||
### **性能回帰テスト**
|
||||
```bash
|
||||
# 削減前後性能比較
|
||||
./scripts/benchmark_mir_reduction.sh
|
||||
```
|
||||
|
||||
## 🎯 **リスク対策**
|
||||
|
||||
### **高リスク箇所**
|
||||
1. **配列操作intrinsic化**: パフォーマンス影響大
|
||||
2. **BoxField統合**: Box型システムとの整合性
|
||||
3. **Effect分類変更**: 最適化ロジック全面見直し
|
||||
|
||||
### **対策**
|
||||
- **プロトタイプ実装**: 高リスク箇所の事前検証
|
||||
- **性能測定**: 各段階での性能チェック
|
||||
- **ロールバック**: 問題発生時の迅速復旧
|
||||
|
||||
---
|
||||
|
||||
**分析完了**: 2025年8月17日
|
||||
**実装開始**: 2025年8月18日
|
||||
**完了予定**: 2025年9月21日
|
||||
@ -1,267 +0,0 @@
|
||||
# nyash.linkシステム設計 - モジュール・依存関係管理革命
|
||||
|
||||
## 🎯 設計背景
|
||||
|
||||
### 📊 現状調査結果
|
||||
- **include使用状況**: 主にexamples/text_adventureで10件程度、実用性は限定的
|
||||
- **usingキーワード**: **未実装**(トークナイザーにも存在しない)
|
||||
- **namespace設計**: Phase 9.75eで仕様完成、実装待ち
|
||||
|
||||
### 🌟 Gemini先生の推奨
|
||||
> 「技術的に非常に妥当であり、現代的なプログラミング言語の設計として強く推奨される」
|
||||
|
||||
**結論**: includeほぼ未使用 + using未実装 = 完全に新設計で進められる!🎉
|
||||
|
||||
## 🚀 設計方針
|
||||
|
||||
### 💡 基本コンセプト
|
||||
```
|
||||
依存関係管理(nyash.link) + モジュールインポート(using) = 完璧な統合
|
||||
```
|
||||
|
||||
### 🎯 他言語成功モデル
|
||||
- **Rust**: `Cargo.toml + mod/use` - 厳格で分かりやすい
|
||||
- **Node.js**: `package.json + import/export` - エコシステム成功
|
||||
- **Python**: `pyproject.toml + import` - 依存関係分離
|
||||
|
||||
## 📋 nyash.linkファイル仕様
|
||||
|
||||
### 基本フォーマット
|
||||
```toml
|
||||
# nyash.link (プロジェクトルート)
|
||||
[project]
|
||||
name = "my-nyash-project"
|
||||
version = "0.1.0"
|
||||
description = "素晴らしいNyashプロジェクト"
|
||||
|
||||
[dependencies]
|
||||
# 標準ライブラリ
|
||||
nyashstd = { path = "./stdlib/nyashstd.hako" }
|
||||
|
||||
# ユーザーライブラリ
|
||||
mylib = { path = "./libs/mylib.hako" }
|
||||
utils = { path = "./src/utils.hako" }
|
||||
|
||||
# 将来の外部パッケージ(例)
|
||||
# http_client = { version = "1.0.0", registry = "nyash-pkg" }
|
||||
|
||||
[search_paths]
|
||||
stdlib = "./stdlib/"
|
||||
libs = "./libs/"
|
||||
src = "./src/"
|
||||
|
||||
[build]
|
||||
entry_point = "./src/main.hako"
|
||||
```
|
||||
|
||||
### 依存関係タイプ
|
||||
|
||||
#### 1. **ローカル依存**
|
||||
```toml
|
||||
[dependencies]
|
||||
my_module = { path = "./src/my_module.hako" }
|
||||
```
|
||||
|
||||
#### 2. **標準ライブラリ**
|
||||
```toml
|
||||
[dependencies]
|
||||
nyashstd = { stdlib = true } # 特別扱い
|
||||
```
|
||||
|
||||
#### 3. **将来の外部パッケージ**
|
||||
```toml
|
||||
[dependencies]
|
||||
awesome_lib = { version = "^1.2.0", registry = "nyash-pkg" }
|
||||
```
|
||||
|
||||
## 🔧 usingシステム設計
|
||||
|
||||
### 1. トークナイザー拡張
|
||||
```rust
|
||||
// src/tokenizer.rs に追加
|
||||
pub enum TokenType {
|
||||
// 既存...
|
||||
USING, // using (モジュールインポート)
|
||||
NAMESPACE, // namespace (名前空間宣言)
|
||||
}
|
||||
```
|
||||
|
||||
### 2. パーサー拡張
|
||||
```rust
|
||||
// AST拡張
|
||||
pub enum Statement {
|
||||
// 既存...
|
||||
UsingStatement {
|
||||
module_path: Vec<String>, // ["nyashstd", "string"]
|
||||
alias: Option<String>, // using nyashstd.string as str
|
||||
},
|
||||
NamespaceDeclaration {
|
||||
name: String,
|
||||
body: Vec<Statement>,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 基本構文
|
||||
```nyash
|
||||
// ===== using構文パターン =====
|
||||
|
||||
// パターンA: 名前空間全体
|
||||
using nyashstd
|
||||
string.upper("hello") // nyashstd.string.upper
|
||||
math.sin(3.14) // nyashstd.math.sin
|
||||
|
||||
// パターンB: 特定機能(将来拡張)
|
||||
using nyashstd.string
|
||||
upper("hello") // string.upperを直接
|
||||
|
||||
// パターンC: エイリアス(将来拡張)
|
||||
using nyashstd.string as str
|
||||
str.upper("hello")
|
||||
|
||||
// パターンD: 完全修飾名(常時利用可能)
|
||||
nyashstd.string.upper("hello") // using不要
|
||||
```
|
||||
|
||||
## 📁 推奨ディレクトリ構造
|
||||
|
||||
### 基本プロジェクト構造
|
||||
```
|
||||
my-nyash-project/
|
||||
├── nyash.link # 依存関係定義
|
||||
├── src/
|
||||
│ ├── main.hako # エントリーポイント
|
||||
│ ├── utils.hako # ユーティリティモジュール
|
||||
│ └── models/
|
||||
│ └── user.hako # モデル定義
|
||||
├── libs/ # プロジェクト固有ライブラリ
|
||||
│ └── mylib.hako
|
||||
├── stdlib/ # 標準ライブラリ(システム配布)
|
||||
│ └── nyashstd.hako
|
||||
└── tests/ # テストファイル
|
||||
└── test_main.hako
|
||||
```
|
||||
|
||||
### 標準ライブラリ構造
|
||||
```
|
||||
stdlib/
|
||||
├── nyashstd.hako # メインエントリー
|
||||
├── string/
|
||||
│ └── mod.hako # string関連機能
|
||||
├── math/
|
||||
│ └── mod.hako # 数学関数
|
||||
├── http/
|
||||
│ └── mod.hako # HTTP関連
|
||||
└── io/
|
||||
└── mod.hako # I/O関連
|
||||
```
|
||||
|
||||
## 🔄 動作フロー
|
||||
|
||||
### 1. プロジェクト初期化
|
||||
```bash
|
||||
# 将来のCLI例
|
||||
nyash init my-project # nyash.linkテンプレート生成
|
||||
cd my-project
|
||||
```
|
||||
|
||||
### 2. 実行時解決
|
||||
```
|
||||
main.hako実行
|
||||
↓
|
||||
nyash.link読み込み
|
||||
↓
|
||||
using nyashstd解析
|
||||
↓
|
||||
./stdlib/nyashstd.hako読み込み
|
||||
↓
|
||||
namespace nyashstd解析・登録
|
||||
↓
|
||||
string.upper()利用可能
|
||||
```
|
||||
|
||||
### 3. 名前解決アルゴリズム
|
||||
```
|
||||
string.upper() 呼び出し
|
||||
↓
|
||||
1. ローカルスコープ検索
|
||||
2. usingでインポートされた名前空間検索
|
||||
3. 完全修飾名として解釈
|
||||
4. エラー(未定義)
|
||||
```
|
||||
|
||||
## 🧪 実装段階
|
||||
|
||||
### Phase 1: 最小実装
|
||||
```nyash
|
||||
// ✅ 実装目標
|
||||
using mylib // 単純パス解決
|
||||
mylib.hello() // 関数呼び出し
|
||||
|
||||
// nyash.link
|
||||
[dependencies]
|
||||
mylib = { path = "./mylib.hako" }
|
||||
```
|
||||
|
||||
### Phase 2: 名前空間サポート
|
||||
```nyash
|
||||
// ✅ 実装目標
|
||||
using nyashstd
|
||||
string.upper("hello")
|
||||
|
||||
// nyashstd.hako
|
||||
namespace nyashstd {
|
||||
static box string {
|
||||
static upper(str) { ... }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 3: 高度機能
|
||||
- エイリアス(`using ... as ...`)
|
||||
- 選択インポート(`using nyashstd.string`)
|
||||
- 循環依存検出
|
||||
- パッケージレジストリ連携
|
||||
|
||||
## ⚡ 実装優先順位
|
||||
|
||||
### 🚨 Critical(即時)
|
||||
1. **UsingTokenizer実装** - Token::USINGを追加
|
||||
2. **基本パーサー** - using文AST構築
|
||||
3. **nyash.link解析** - TOML読み込み機能
|
||||
|
||||
### ⚡ High(今週)
|
||||
4. **名前解決エンジン** - モジュール→ファイル解決
|
||||
5. **基本テスト** - using mylib動作確認
|
||||
6. **エラー処理** - 未定義モジュール等
|
||||
|
||||
### 📝 Medium(来週)
|
||||
7. **namespace構文** - static box解析
|
||||
8. **標準ライブラリ設計** - nyashstd.hako作成
|
||||
9. **完全修飾名** - nyashstd.string.upper()
|
||||
|
||||
### 🔮 Future(今後)
|
||||
10. **IDE連携** - Language Server補完
|
||||
11. **パッケージマネージャー** - 外部レジストリ
|
||||
12. **循環依存検出** - 高度エラー処理
|
||||
|
||||
## 🎉 期待効果
|
||||
|
||||
### 📈 開発体験向上
|
||||
- **IDE補完**: `ny`→全標準機能表示
|
||||
- **探索可能性**: モジュール構造が明確
|
||||
- **エラー削減**: 名前衝突・未定義の事前検出
|
||||
|
||||
### 🏗️ プロジェクト管理
|
||||
- **依存関係明確化**: nyash.linkで一元管理
|
||||
- **ビルド再現性**: 他環境での確実な動作
|
||||
- **スケーラビリティ**: 大規模プロジェクト対応
|
||||
|
||||
### 🌍 エコシステム発展
|
||||
- **ライブラリ共有**: 標準化されたモジュール形式
|
||||
- **コミュニティ成長**: パッケージレジストリ基盤
|
||||
- **言語成熟度**: モダンな言語仕様
|
||||
|
||||
---
|
||||
|
||||
**🐾 この設計でNyashが真にモダンなプログラミング言語になるにゃ!**
|
||||
@ -1,654 +0,0 @@
|
||||
# BID×usingシステム統合:技術実装詳細
|
||||
|
||||
## 🎯 統合設計の核心
|
||||
|
||||
### 📊 既存システムとの整合性
|
||||
- ✅ **MIR ExternCall**: 既にFFI-ABI対応実装済み
|
||||
- ✅ **WASM RuntimeImports**: BID→WASM自動生成基盤あり
|
||||
- ✅ **VM ExternStub**: スタブ実行環境実装済み
|
||||
- 🔧 **統合課題**: usingシステムとBIDの橋渡し実装
|
||||
|
||||
### 🚀 統合アーキテクチャ概要
|
||||
```
|
||||
User Code (using statements)
|
||||
↓
|
||||
UniversalNamespaceRegistry
|
||||
↓
|
||||
CallTarget Resolution
|
||||
↓ ↓ ↓
|
||||
Builtin FFI-ABI NyashModule
|
||||
↓ ↓ ↓
|
||||
MIR Generation (BuiltinCall/ExternCall/ModuleCall)
|
||||
↓
|
||||
Backend Execution (VM/WASM/AOT)
|
||||
```
|
||||
|
||||
## 🏗️ 詳細技術実装
|
||||
|
||||
### 1. BID定義システム
|
||||
|
||||
#### **BIDファイル構造拡張**
|
||||
```yaml
|
||||
# apis/enhanced_canvas.yaml
|
||||
version: 1
|
||||
metadata:
|
||||
name: "Enhanced Canvas API"
|
||||
description: "Extended Canvas API with batch operations"
|
||||
target_environments: ["browser", "node-canvas", "skia"]
|
||||
nyash_namespace: "canvas_api" # usingで使用する名前空間
|
||||
|
||||
interfaces:
|
||||
- name: canvas_api.canvas
|
||||
box: Canvas
|
||||
methods:
|
||||
# 基本描画
|
||||
- name: fillRect
|
||||
params:
|
||||
- {string: canvas_id, description: "Canvas element ID"}
|
||||
- {i32: x, description: "X coordinate"}
|
||||
- {i32: y, description: "Y coordinate"}
|
||||
- {i32: width, description: "Rectangle width"}
|
||||
- {i32: height, description: "Rectangle height"}
|
||||
- {string: color, description: "Fill color (CSS format)"}
|
||||
returns: void
|
||||
effect: io
|
||||
optimization_hints:
|
||||
batch_compatible: true # バッチ処理可能
|
||||
gpu_accelerated: true # GPU加速対応
|
||||
|
||||
# バッチ描画(最適化版)
|
||||
- name: fillRectBatch
|
||||
params:
|
||||
- {string: canvas_id}
|
||||
- {array_of_rect: rects, element_type: "CanvasRect"}
|
||||
returns: void
|
||||
effect: io
|
||||
optimization_hints:
|
||||
prefer_over: ["fillRect"] # 複数fillRectの代替
|
||||
min_batch_size: 3
|
||||
|
||||
# テキスト描画
|
||||
- name: fillText
|
||||
params:
|
||||
- {string: canvas_id}
|
||||
- {string: text}
|
||||
- {i32: x}
|
||||
- {i32: y}
|
||||
- {string: font}
|
||||
- {string: color}
|
||||
returns: void
|
||||
effect: io
|
||||
|
||||
# カスタム型定義
|
||||
custom_types:
|
||||
- name: CanvasRect
|
||||
fields:
|
||||
- {i32: x}
|
||||
- {i32: y}
|
||||
- {i32: width}
|
||||
- {i32: height}
|
||||
- {string: color}
|
||||
```
|
||||
|
||||
#### **BID読み込み・検証システム**
|
||||
```rust
|
||||
// 新ファイル: src/bid/mod.rs
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct BidDefinition {
|
||||
pub version: u32,
|
||||
pub metadata: BidMetadata,
|
||||
pub interfaces: Vec<BidInterface>,
|
||||
pub custom_types: Option<Vec<BidCustomType>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct BidMetadata {
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub target_environments: Vec<String>,
|
||||
pub nyash_namespace: String, // using文で使用する名前空間名
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct BidInterface {
|
||||
pub name: String, // "canvas_api.canvas"
|
||||
pub box_name: String, // "Canvas"
|
||||
pub methods: Vec<BidMethod>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct BidMethod {
|
||||
pub name: String,
|
||||
pub params: Vec<BidParam>,
|
||||
pub returns: BidType,
|
||||
pub effect: BidEffect,
|
||||
pub optimization_hints: Option<BidOptimizationHints>,
|
||||
pub description: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct BidOptimizationHints {
|
||||
pub batch_compatible: Option<bool>,
|
||||
pub gpu_accelerated: Option<bool>,
|
||||
pub prefer_over: Option<Vec<String>>,
|
||||
pub min_batch_size: Option<usize>,
|
||||
}
|
||||
|
||||
impl BidDefinition {
|
||||
pub fn load_from_file(path: &Path) -> Result<Self, BidError> {
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
let bid: BidDefinition = serde_yaml::from_str(&content)?;
|
||||
|
||||
// バリデーション
|
||||
bid.validate()?;
|
||||
|
||||
Ok(bid)
|
||||
}
|
||||
|
||||
pub fn validate(&self) -> Result<(), BidError> {
|
||||
// バージョン確認
|
||||
if self.version > 1 {
|
||||
return Err(BidError::UnsupportedVersion(self.version));
|
||||
}
|
||||
|
||||
// 名前空間重複チェック
|
||||
let mut interface_names = HashSet::new();
|
||||
for interface in &self.interfaces {
|
||||
if interface_names.contains(&interface.name) {
|
||||
return Err(BidError::DuplicateInterface(interface.name.clone()));
|
||||
}
|
||||
interface_names.insert(interface.name.clone());
|
||||
}
|
||||
|
||||
// パラメータ型確認
|
||||
for interface in &self.interfaces {
|
||||
for method in &interface.methods {
|
||||
for param in &method.params {
|
||||
self.validate_type(¶m.param_type)?;
|
||||
}
|
||||
self.validate_type(&method.returns)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn resolve_method(&self, box_name: &str, method_name: &str)
|
||||
-> Option<&BidMethod> {
|
||||
|
||||
for interface in &self.interfaces {
|
||||
// インターフェース名から最後の部分を取得
|
||||
// "canvas_api.canvas" → "canvas"
|
||||
let interface_box_name = interface.name.split('.').last().unwrap_or(&interface.name);
|
||||
|
||||
if interface_box_name == box_name {
|
||||
for method in &interface.methods {
|
||||
if method.name == method_name {
|
||||
return Some(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 統合名前空間レジストリ詳細
|
||||
|
||||
#### **UniversalNamespaceRegistry実装**
|
||||
```rust
|
||||
// src/registry/universal.rs
|
||||
use crate::stdlib::BuiltinStdlib;
|
||||
use crate::bid::BidDefinition;
|
||||
use crate::module::ExternalModule;
|
||||
use crate::mir::Effect;
|
||||
|
||||
pub struct UniversalNamespaceRegistry {
|
||||
/// 組み込み標準ライブラリ
|
||||
builtin_stdlib: Arc<BuiltinStdlib>,
|
||||
|
||||
/// FFI-ABI定義(BID)
|
||||
bid_definitions: HashMap<String, Arc<BidDefinition>>,
|
||||
|
||||
/// Nyashモジュール(従来)
|
||||
nyash_modules: HashMap<String, Arc<ExternalModule>>,
|
||||
|
||||
/// ファイル別usingコンテキスト
|
||||
using_contexts: Arc<RwLock<HashMap<String, UsingContext>>>,
|
||||
|
||||
/// 最適化情報キャッシュ
|
||||
optimization_cache: Arc<RwLock<OptimizationCache>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UsingContext {
|
||||
pub file_id: String,
|
||||
pub builtin_namespaces: Vec<String>, // ["nyashstd"]
|
||||
pub bid_namespaces: Vec<String>, // ["canvas_api", "console_api"]
|
||||
pub module_namespaces: Vec<String>, // ["mylib", "utils"]
|
||||
}
|
||||
|
||||
impl UniversalNamespaceRegistry {
|
||||
pub fn new() -> Self {
|
||||
UniversalNamespaceRegistry {
|
||||
builtin_stdlib: Arc::new(BuiltinStdlib::new()),
|
||||
bid_definitions: HashMap::new(),
|
||||
nyash_modules: HashMap::new(),
|
||||
using_contexts: Arc::new(RwLock::new(HashMap::new())),
|
||||
optimization_cache: Arc::new(RwLock::new(OptimizationCache::new())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_from_nyash_link(&mut self, nyash_link: &NyashLink)
|
||||
-> Result<(), RegistryError> {
|
||||
|
||||
// BID依存関係読み込み
|
||||
for (namespace_name, dependency) in &nyash_link.dependencies {
|
||||
match dependency {
|
||||
Dependency::Bid { bid_path, .. } => {
|
||||
let bid = BidDefinition::load_from_file(Path::new(bid_path))?;
|
||||
self.bid_definitions.insert(namespace_name.clone(), Arc::new(bid));
|
||||
},
|
||||
Dependency::Path { path } => {
|
||||
let module = ExternalModule::load_from_file(Path::new(path))?;
|
||||
self.hako_modules.insert(namespace_name.clone(), Arc::new(module));
|
||||
},
|
||||
Dependency::Builtin { .. } => {
|
||||
// 組み込みライブラリは既に初期化済み
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 統合using処理
|
||||
pub fn process_using(&mut self, namespace_name: &str, file_id: &str)
|
||||
-> Result<(), RuntimeError> {
|
||||
|
||||
let mut contexts = self.using_contexts.write().unwrap();
|
||||
let context = contexts.entry(file_id.to_string()).or_insert_with(|| {
|
||||
UsingContext {
|
||||
file_id: file_id.to_string(),
|
||||
builtin_namespaces: Vec::new(),
|
||||
bid_namespaces: Vec::new(),
|
||||
module_namespaces: Vec::new(),
|
||||
}
|
||||
});
|
||||
|
||||
// 組み込み標準ライブラリチェック
|
||||
if self.builtin_stdlib.has_namespace(namespace_name) {
|
||||
if !context.builtin_namespaces.contains(&namespace_name.to_string()) {
|
||||
context.builtin_namespaces.push(namespace_name.to_string());
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// BID定義チェック
|
||||
if let Some(bid) = self.bid_definitions.get(namespace_name) {
|
||||
if !context.bid_namespaces.contains(&namespace_name.to_string()) {
|
||||
context.bid_namespaces.push(namespace_name.to_string());
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Nyashモジュールチェック
|
||||
if let Some(_module) = self.hako_modules.get(namespace_name) {
|
||||
if !context.module_namespaces.contains(&namespace_name.to_string()) {
|
||||
context.module_namespaces.push(namespace_name.to_string());
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Err(RuntimeError::UndefinedNamespace(namespace_name.to_string()))
|
||||
}
|
||||
|
||||
/// 統合関数解決
|
||||
pub fn resolve_call(&self, file_id: &str, call_path: &[String])
|
||||
-> Result<ResolvedCall, RuntimeError> {
|
||||
|
||||
if call_path.len() != 2 {
|
||||
return Err(RuntimeError::InvalidCallPath(call_path.join(".")));
|
||||
}
|
||||
|
||||
let box_name = &call_path[0];
|
||||
let method_name = &call_path[1];
|
||||
|
||||
let contexts = self.using_contexts.read().unwrap();
|
||||
if let Some(context) = contexts.get(file_id) {
|
||||
|
||||
// 1. 組み込み標準ライブラリ解決
|
||||
for namespace in &context.builtin_namespaces {
|
||||
if let Some(method) = self.builtin_stdlib.resolve_method(namespace, box_name, method_name) {
|
||||
return Ok(ResolvedCall::Builtin {
|
||||
namespace: namespace.clone(),
|
||||
box_name: box_name.clone(),
|
||||
method_name: method_name.clone(),
|
||||
method_info: method,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 2. BID定義解決
|
||||
for namespace in &context.bid_namespaces {
|
||||
if let Some(bid) = self.bid_definitions.get(namespace) {
|
||||
if let Some(method) = bid.resolve_method(box_name, method_name) {
|
||||
return Ok(ResolvedCall::BidCall {
|
||||
namespace: namespace.clone(),
|
||||
interface_name: format!("{}.{}", namespace, box_name),
|
||||
method_name: method_name.clone(),
|
||||
method_info: method.clone(),
|
||||
bid_definition: bid.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Nyashモジュール解決
|
||||
for namespace in &context.module_namespaces {
|
||||
if let Some(module) = self.hako_modules.get(namespace) {
|
||||
if let Some(function) = module.resolve_function(box_name, method_name) {
|
||||
return Ok(ResolvedCall::ModuleCall {
|
||||
namespace: namespace.clone(),
|
||||
module_name: namespace.clone(),
|
||||
function_name: format!("{}.{}", box_name, method_name),
|
||||
function_info: function,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(RuntimeError::UndefinedMethod(format!("{}.{}", box_name, method_name)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ResolvedCall {
|
||||
Builtin {
|
||||
namespace: String,
|
||||
box_name: String,
|
||||
method_name: String,
|
||||
method_info: BuiltinMethodInfo,
|
||||
},
|
||||
BidCall {
|
||||
namespace: String,
|
||||
interface_name: String,
|
||||
method_name: String,
|
||||
method_info: BidMethod,
|
||||
bid_definition: Arc<BidDefinition>,
|
||||
},
|
||||
ModuleCall {
|
||||
namespace: String,
|
||||
module_name: String,
|
||||
function_name: String,
|
||||
function_info: ModuleFunctionInfo,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### 3. MIR生成統合
|
||||
|
||||
#### **統合MIR Builder**
|
||||
```rust
|
||||
// src/mir/builder.rs拡張
|
||||
impl MirBuilder {
|
||||
pub fn build_unified_method_call(&mut self, resolved_call: ResolvedCall, args: Vec<ValueId>)
|
||||
-> Result<Option<ValueId>, MirError> {
|
||||
|
||||
match resolved_call {
|
||||
ResolvedCall::Builtin { method_info, .. } => {
|
||||
let result = self.new_value_id();
|
||||
|
||||
self.emit(MirInstruction::BuiltinCall {
|
||||
qualified_name: method_info.qualified_name(),
|
||||
args,
|
||||
result,
|
||||
effect: method_info.effect(),
|
||||
});
|
||||
|
||||
Ok(Some(result))
|
||||
},
|
||||
|
||||
ResolvedCall::BidCall { interface_name, method_name, method_info, .. } => {
|
||||
let result = if method_info.returns == BidType::Void {
|
||||
None
|
||||
} else {
|
||||
Some(self.new_value_id())
|
||||
};
|
||||
|
||||
self.emit(MirInstruction::ExternCall {
|
||||
interface: interface_name,
|
||||
method: method_name,
|
||||
args,
|
||||
result,
|
||||
effect: self.bid_effect_to_mir_effect(&method_info.effect),
|
||||
bid_signature: BidSignature::from_method(&method_info),
|
||||
});
|
||||
|
||||
Ok(result)
|
||||
},
|
||||
|
||||
ResolvedCall::ModuleCall { module_name, function_name, function_info, .. } => {
|
||||
let result = self.new_value_id();
|
||||
|
||||
self.emit(MirInstruction::ModuleCall {
|
||||
module: module_name,
|
||||
function: function_name,
|
||||
args,
|
||||
result,
|
||||
effect: Effect::Io, // Nyashモジュールはデフォルトでio
|
||||
});
|
||||
|
||||
Ok(Some(result))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn bid_effect_to_mir_effect(&self, bid_effect: &BidEffect) -> Effect {
|
||||
match bid_effect {
|
||||
BidEffect::Pure => Effect::Pure,
|
||||
BidEffect::Mut => Effect::Mut,
|
||||
BidEffect::Io => Effect::Io,
|
||||
BidEffect::Control => Effect::Control,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. バックエンド統合
|
||||
|
||||
#### **WASM生成統合**
|
||||
```rust
|
||||
// src/backend/wasm/codegen.rs拡張
|
||||
impl WasmCodegen {
|
||||
pub fn generate_unified_call(&mut self, instruction: &MirInstruction)
|
||||
-> Result<(), WasmError> {
|
||||
|
||||
match instruction {
|
||||
MirInstruction::ExternCall { interface, method, args, bid_signature, .. } => {
|
||||
// BIDから自動生成されたWASM import名
|
||||
let wasm_import_name = self.bid_to_wasm_import_name(interface, method);
|
||||
|
||||
// 引数の型変換・マーシャリング
|
||||
let marshalled_args = self.marshal_args_for_wasm(args, &bid_signature.params)?;
|
||||
|
||||
// WASM関数呼び出し生成
|
||||
self.emit_call(&wasm_import_name, &marshalled_args)?;
|
||||
|
||||
// 戻り値のアンマーシャリング
|
||||
if bid_signature.returns != BidType::Void {
|
||||
self.unmarshal_return_value(&bid_signature.returns)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
},
|
||||
|
||||
// 他の命令は既存実装
|
||||
_ => self.generate_instruction_legacy(instruction),
|
||||
}
|
||||
}
|
||||
|
||||
fn bid_to_wasm_import_name(&self, interface: &str, method: &str) -> String {
|
||||
// "canvas_api.canvas" + "fillRect" → "canvas_api_canvas_fillRect"
|
||||
format!("{}_{}", interface.replace(".", "_"), method)
|
||||
}
|
||||
|
||||
fn marshal_args_for_wasm(&mut self, args: &[ValueId], params: &[BidParam])
|
||||
-> Result<Vec<WasmValue>, WasmError> {
|
||||
|
||||
let mut marshalled = Vec::new();
|
||||
|
||||
for (i, param) in params.iter().enumerate() {
|
||||
let arg_value = self.get_value(args[i])?;
|
||||
|
||||
match ¶m.param_type {
|
||||
BidType::String => {
|
||||
// 文字列を (ptr, len) にマーシャル
|
||||
let (ptr, len) = self.string_to_wasm_memory(&arg_value)?;
|
||||
marshalled.push(WasmValue::I32(ptr));
|
||||
marshalled.push(WasmValue::I32(len));
|
||||
},
|
||||
BidType::I32 => {
|
||||
marshalled.push(WasmValue::I32(arg_value.to_i32()?));
|
||||
},
|
||||
BidType::F64 => {
|
||||
marshalled.push(WasmValue::F64(arg_value.to_f64()?));
|
||||
},
|
||||
// その他の型...
|
||||
}
|
||||
}
|
||||
|
||||
Ok(marshalled)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **VM実行統合**
|
||||
```rust
|
||||
// src/backend/vm.rs拡張
|
||||
impl VmBackend {
|
||||
pub fn execute_unified_instruction(&mut self, instruction: &MirInstruction)
|
||||
-> Result<(), VmError> {
|
||||
|
||||
match instruction {
|
||||
MirInstruction::ExternCall { interface, method, args, bid_signature, .. } => {
|
||||
// VM環境ではスタブまたはネイティブ呼び出し
|
||||
let evaluated_args = self.evaluate_args(args)?;
|
||||
|
||||
if let Some(native_impl) = self.find_native_implementation(interface, method) {
|
||||
// ネイティブ実装がある場合(例:ファイルI/O)
|
||||
let result = native_impl.call(evaluated_args, bid_signature)?;
|
||||
if let Some(result_id) = &instruction.result {
|
||||
self.set_value(*result_id, result);
|
||||
}
|
||||
} else {
|
||||
// スタブ実装(ログ出力等)
|
||||
self.execute_stub_call(interface, method, evaluated_args, bid_signature)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
},
|
||||
|
||||
// 他の命令は既存実装
|
||||
_ => self.execute_instruction_legacy(instruction),
|
||||
}
|
||||
}
|
||||
|
||||
fn find_native_implementation(&self, interface: &str, method: &str)
|
||||
-> Option<&dyn NativeImplementation> {
|
||||
|
||||
// VM環境で利用可能なネイティブ実装を検索
|
||||
match (interface, method) {
|
||||
("env.console", "log") => Some(&self.console_impl),
|
||||
("env.filesystem", "read") => Some(&self.filesystem_impl),
|
||||
("env.filesystem", "write") => Some(&self.filesystem_impl),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🧪 統合テスト戦略
|
||||
|
||||
### Phase別テスト実装
|
||||
|
||||
#### **Phase 0: 基本統合テスト**
|
||||
```nyash
|
||||
# test_basic_integration.hako
|
||||
using nyashstd
|
||||
|
||||
# 組み込み標準ライブラリのみ
|
||||
assert(string.upper("test") == "TEST")
|
||||
assert(math.sin(0) == 0)
|
||||
```
|
||||
|
||||
#### **Phase 1: BID統合テスト**
|
||||
```nyash
|
||||
# test_bid_integration.hako
|
||||
using nyashstd
|
||||
using console_api
|
||||
|
||||
# 組み込み + FFI-ABI
|
||||
string.upper("hello") # 組み込み
|
||||
console.log("Testing") # FFI-ABI
|
||||
```
|
||||
|
||||
#### **Phase 2: 完全統合テスト**
|
||||
```nyash
|
||||
# test_full_integration.hako
|
||||
using nyashstd
|
||||
using console_api
|
||||
using mylib
|
||||
|
||||
# 3種類すべて
|
||||
string.upper("test") # 組み込み
|
||||
console.log("Integration") # FFI-ABI
|
||||
mylib.process("data") # Nyashモジュール
|
||||
```
|
||||
|
||||
### エラーハンドリングテスト
|
||||
```nyash
|
||||
# test_error_handling.hako
|
||||
try {
|
||||
using nonexistent_api
|
||||
} catch error {
|
||||
assert(error.type == "UndefinedNamespace")
|
||||
}
|
||||
|
||||
try {
|
||||
console.nonexistent_method("test")
|
||||
} catch error {
|
||||
assert(error.type == "UndefinedMethod")
|
||||
assert(error.message.contains("Available methods:"))
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 実装マイルストーン
|
||||
|
||||
### ✅ Phase 0完了条件
|
||||
- [ ] UniversalNamespaceRegistry基盤実装
|
||||
- [ ] 組み込み標準ライブラリ統合
|
||||
- [ ] 基本using文処理
|
||||
- [ ] MIR BuiltinCall生成
|
||||
|
||||
### ✅ Phase 1完了条件
|
||||
- [ ] BID定義読み込み・検証
|
||||
- [ ] BID→MIR ExternCall統合
|
||||
- [ ] WASM RuntimeImports自動生成
|
||||
- [ ] VM スタブ実行
|
||||
|
||||
### ✅ Phase 2完了条件
|
||||
- [ ] Nyashモジュール統合
|
||||
- [ ] 統合エラーハンドリング
|
||||
- [ ] 最適化キャッシュ
|
||||
- [ ] 全バックエンド対応
|
||||
|
||||
---
|
||||
|
||||
**🎯 この詳細実装により、BIDとusingシステムの完全統合が実現でき、「なんでもAPI計画」の技術基盤が完成するにゃ!🚀🐱**
|
||||
@ -1,456 +0,0 @@
|
||||
# 組み込みnyashstd名前空間アーキテクチャ設計
|
||||
|
||||
## 🏗️ 技術的実装アーキテクチャ
|
||||
|
||||
### 📊 現在のインタープリター構造分析
|
||||
|
||||
#### **NyashInterpreter構造**
|
||||
```rust
|
||||
pub struct NyashInterpreter {
|
||||
pub(super) shared: SharedState, // 共有状態
|
||||
pub(super) local_vars: HashMap<String, SharedNyashBox>,
|
||||
pub(super) outbox_vars: HashMap<String, SharedNyashBox>,
|
||||
// その他の制御フロー状態...
|
||||
}
|
||||
```
|
||||
|
||||
#### **設計判断:SharedStateに組み込み**
|
||||
- **理由**: 標準ライブラリは不変・全インタープリターで共有可能
|
||||
- **利点**: メモリ効率、パフォーマンス向上
|
||||
- **実装**: SharedStateに`builtin_stdlib`フィールド追加
|
||||
|
||||
## 🌟 最適化されたアーキテクチャ設計
|
||||
|
||||
### 1. SharedState拡張
|
||||
|
||||
#### **src/interpreter/core.rs**
|
||||
```rust
|
||||
#[derive(Clone)]
|
||||
pub struct SharedState {
|
||||
// 既存フィールド...
|
||||
pub global_vars: Arc<RwLock<HashMap<String, SharedNyashBox>>>,
|
||||
pub functions: Arc<RwLock<HashMap<String, Function>>>,
|
||||
pub box_definitions: Arc<RwLock<HashMap<String, Box<UserDefinedBoxDefinition>>>>,
|
||||
pub loop_counter: Arc<AtomicU64>,
|
||||
pub included_files: Arc<RwLock<HashSet<String>>>,
|
||||
|
||||
// 🌟 新規追加: 組み込み標準ライブラリ
|
||||
pub builtin_stdlib: Arc<BuiltinStdlib>,
|
||||
pub using_imports: Arc<RwLock<HashMap<String, UsingContext>>>, // ファイル別インポート管理
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UsingContext {
|
||||
pub imported_namespaces: Vec<String>, // ["nyashstd"]
|
||||
pub file_id: String, // インポート元ファイル識別
|
||||
}
|
||||
```
|
||||
|
||||
### 2. BuiltinStdlib効率化設計
|
||||
|
||||
#### **新ファイル: src/stdlib/builtin.rs**
|
||||
```rust
|
||||
//! 🚀 高性能組み込み標準ライブラリ
|
||||
//!
|
||||
//! 設計方針:
|
||||
//! - Zero-allocation関数実行
|
||||
//! - 高速名前解決
|
||||
//! - 既存Box実装の最大活用
|
||||
|
||||
use crate::boxes::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// 組み込み標準ライブラリのメイン構造体
|
||||
#[derive(Debug)]
|
||||
pub struct BuiltinStdlib {
|
||||
/// 高速アクセス用:フラットな関数マップ
|
||||
/// "string.upper" -> BuiltinFunction
|
||||
pub flat_functions: HashMap<String, BuiltinFunction>,
|
||||
|
||||
/// IDE補完用:階層構造
|
||||
/// "nyashstd" -> { "string" -> ["upper", "lower", ...] }
|
||||
pub hierarchical_map: HashMap<String, HashMap<String, Vec<String>>>,
|
||||
}
|
||||
|
||||
/// 組み込み関数の実装
|
||||
pub struct BuiltinFunction {
|
||||
pub namespace: &'static str, // "nyashstd"
|
||||
pub box_name: &'static str, // "string"
|
||||
pub method_name: &'static str, // "upper"
|
||||
pub implementation: BuiltinMethodImpl,
|
||||
pub arg_count: Option<usize>, // None = 可変長
|
||||
pub description: &'static str, // エラーメッセージ・ヘルプ用
|
||||
}
|
||||
|
||||
/// 高性能関数実装
|
||||
pub type BuiltinMethodImpl = fn(&[Box<dyn NyashBox>]) -> Result<Box<dyn NyashBox>, RuntimeError>;
|
||||
|
||||
impl BuiltinStdlib {
|
||||
/// 🚀 標準ライブラリ初期化(起動時1回のみ)
|
||||
pub fn new() -> Self {
|
||||
let mut stdlib = BuiltinStdlib {
|
||||
flat_functions: HashMap::new(),
|
||||
hierarchical_map: HashMap::new(),
|
||||
};
|
||||
|
||||
// 標準関数登録
|
||||
stdlib.register_all_functions();
|
||||
|
||||
stdlib
|
||||
}
|
||||
|
||||
/// ⚡ 高速関数解決
|
||||
pub fn get_function(&self, qualified_name: &str) -> Option<&BuiltinFunction> {
|
||||
// "string.upper" で直接アクセス
|
||||
self.flat_functions.get(qualified_name)
|
||||
}
|
||||
|
||||
/// 🔍 IDE補完用:利用可能関数一覧取得
|
||||
pub fn get_available_methods(&self, namespace: &str, box_name: &str) -> Option<&Vec<String>> {
|
||||
self.hierarchical_map.get(namespace)?.get(box_name)
|
||||
}
|
||||
|
||||
/// 📋 全名前空間取得(IDE補完用)
|
||||
pub fn get_all_namespaces(&self) -> Vec<&String> {
|
||||
self.hierarchical_map.keys().collect()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 標準関数実装(高性能版)
|
||||
|
||||
#### **文字列関数実装**
|
||||
```rust
|
||||
impl BuiltinStdlib {
|
||||
fn register_all_functions(&mut self) {
|
||||
// === nyashstd.string.* ===
|
||||
self.register_function("string.upper", BuiltinFunction {
|
||||
namespace: "nyashstd",
|
||||
box_name: "string",
|
||||
method_name: "upper",
|
||||
implementation: |args| {
|
||||
if args.len() != 1 {
|
||||
return Err(RuntimeError::InvalidArguments(
|
||||
"string.upper(str) takes exactly 1 argument".to_string()
|
||||
));
|
||||
}
|
||||
|
||||
// 🚀 既存StringBox実装活用
|
||||
let input_str = args[0].to_string_box().value;
|
||||
let result = StringBox::new(&input_str.to_uppercase());
|
||||
Ok(Box::new(result))
|
||||
},
|
||||
arg_count: Some(1),
|
||||
description: "Convert string to uppercase",
|
||||
});
|
||||
|
||||
self.register_function("string.lower", BuiltinFunction {
|
||||
namespace: "nyashstd",
|
||||
box_name: "string",
|
||||
method_name: "lower",
|
||||
implementation: |args| {
|
||||
if args.len() != 1 {
|
||||
return Err(RuntimeError::InvalidArguments(
|
||||
"string.lower(str) takes exactly 1 argument".to_string()
|
||||
));
|
||||
}
|
||||
|
||||
let input_str = args[0].to_string_box().value;
|
||||
let result = StringBox::new(&input_str.to_lowercase());
|
||||
Ok(Box::new(result))
|
||||
},
|
||||
arg_count: Some(1),
|
||||
description: "Convert string to lowercase",
|
||||
});
|
||||
|
||||
self.register_function("string.split", BuiltinFunction {
|
||||
namespace: "nyashstd",
|
||||
box_name: "string",
|
||||
method_name: "split",
|
||||
implementation: |args| {
|
||||
if args.len() != 2 {
|
||||
return Err(RuntimeError::InvalidArguments(
|
||||
"string.split(str, separator) takes exactly 2 arguments".to_string()
|
||||
));
|
||||
}
|
||||
|
||||
// 🚀 既存StringBox.split()メソッド活用
|
||||
let string_box = StringBox::new(&args[0].to_string_box().value);
|
||||
let separator = &args[1].to_string_box().value;
|
||||
string_box.split(separator)
|
||||
},
|
||||
arg_count: Some(2),
|
||||
description: "Split string by separator into array",
|
||||
});
|
||||
|
||||
// === nyashstd.math.* ===
|
||||
self.register_function("math.sin", BuiltinFunction {
|
||||
namespace: "nyashstd",
|
||||
box_name: "math",
|
||||
method_name: "sin",
|
||||
implementation: |args| {
|
||||
if args.len() != 1 {
|
||||
return Err(RuntimeError::InvalidArguments(
|
||||
"math.sin(x) takes exactly 1 argument".to_string()
|
||||
));
|
||||
}
|
||||
|
||||
// 🚀 既存MathBox実装活用
|
||||
let math_box = MathBox::new();
|
||||
let x = args[0].to_integer_box().value as f64;
|
||||
let result = math_box.sin(x)?;
|
||||
Ok(result)
|
||||
},
|
||||
arg_count: Some(1),
|
||||
description: "Calculate sine of x (in radians)",
|
||||
});
|
||||
|
||||
// 階層マップも同時構築
|
||||
self.build_hierarchical_map();
|
||||
}
|
||||
|
||||
fn register_function(&mut self, qualified_name: &str, function: BuiltinFunction) {
|
||||
self.flat_functions.insert(qualified_name.to_string(), function);
|
||||
}
|
||||
|
||||
fn build_hierarchical_map(&mut self) {
|
||||
for (qualified_name, function) in &self.flat_functions {
|
||||
let namespace_map = self.hierarchical_map
|
||||
.entry(function.namespace.to_string())
|
||||
.or_insert_with(HashMap::new);
|
||||
|
||||
let method_list = namespace_map
|
||||
.entry(function.box_name.to_string())
|
||||
.or_insert_with(Vec::new);
|
||||
|
||||
method_list.push(function.method_name.to_string());
|
||||
}
|
||||
|
||||
// ソートして一貫性確保
|
||||
for namespace_map in self.hierarchical_map.values_mut() {
|
||||
for method_list in namespace_map.values_mut() {
|
||||
method_list.sort();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. インタープリター統合
|
||||
|
||||
#### **NyashInterpreter拡張**
|
||||
```rust
|
||||
impl NyashInterpreter {
|
||||
/// using文実行
|
||||
pub fn execute_using(&mut self, namespace_name: &str) -> Result<(), RuntimeError> {
|
||||
// 組み込み名前空間存在チェック
|
||||
if !self.shared.builtin_stdlib.hierarchical_map.contains_key(namespace_name) {
|
||||
return Err(RuntimeError::UndefinedNamespace(namespace_name.to_string()));
|
||||
}
|
||||
|
||||
// 現在ファイルのusingコンテキスト更新
|
||||
let file_id = self.get_current_file_id();
|
||||
let mut using_imports = self.shared.using_imports.write().unwrap();
|
||||
|
||||
let context = using_imports.entry(file_id.clone()).or_insert(UsingContext {
|
||||
imported_namespaces: Vec::new(),
|
||||
file_id: file_id.clone(),
|
||||
});
|
||||
|
||||
if !context.imported_namespaces.contains(&namespace_name.to_string()) {
|
||||
context.imported_namespaces.push(namespace_name.to_string());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// ⚡ 高速名前解決:string.upper() → nyashstd.string.upper()
|
||||
pub fn resolve_qualified_call(&self, path: &[String]) -> Option<String> {
|
||||
if path.len() != 2 {
|
||||
return None; // Phase 0では2段階のみ対応
|
||||
}
|
||||
|
||||
let box_name = &path[0];
|
||||
let method_name = &path[1];
|
||||
let file_id = self.get_current_file_id();
|
||||
|
||||
// 現在ファイルのusingインポート確認
|
||||
if let Ok(using_imports) = self.shared.using_imports.read() {
|
||||
if let Some(context) = using_imports.get(&file_id) {
|
||||
for namespace in &context.imported_namespaces {
|
||||
let qualified_name = format!("{}.{}", box_name, method_name);
|
||||
|
||||
// 実際に関数が存在するかチェック
|
||||
if self.shared.builtin_stdlib.get_function(&qualified_name).is_some() {
|
||||
return Some(qualified_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// 🚀 組み込み関数実行
|
||||
pub fn call_builtin_function(&self, qualified_name: &str, args: Vec<Box<dyn NyashBox>>)
|
||||
-> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
|
||||
if let Some(function) = self.shared.builtin_stdlib.get_function(qualified_name) {
|
||||
// 引数数チェック
|
||||
if let Some(expected_count) = function.arg_count {
|
||||
if args.len() != expected_count {
|
||||
return Err(RuntimeError::InvalidArguments(
|
||||
format!("{}.{}() takes exactly {} arguments, got {}",
|
||||
function.box_name, function.method_name,
|
||||
expected_count, args.len())
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// 関数実行
|
||||
(function.implementation)(&args)
|
||||
} else {
|
||||
Err(RuntimeError::UndefinedMethod(qualified_name.to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 式実行統合
|
||||
|
||||
#### **src/interpreter/expressions.rs修正**
|
||||
```rust
|
||||
impl NyashInterpreter {
|
||||
pub fn execute_expression(&mut self, node: &ASTNode) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
match node {
|
||||
// 既存のケース...
|
||||
|
||||
// メソッド呼び出し処理修正
|
||||
ASTNode::MethodCall { object, method, args, .. } => {
|
||||
// オブジェクトが単純な識別子かチェック
|
||||
if let ASTNode::Variable { name: box_name, .. } = object.as_ref() {
|
||||
// using経由での短縮呼び出しチェック
|
||||
let path = vec![box_name.clone(), method.clone()];
|
||||
if let Some(qualified_name) = self.resolve_qualified_call(&path) {
|
||||
// 引数評価
|
||||
let evaluated_args = self.evaluate_arguments(args)?;
|
||||
// 組み込み関数実行
|
||||
return self.call_builtin_function(&qualified_name, evaluated_args);
|
||||
}
|
||||
}
|
||||
|
||||
// 既存のメソッド呼び出し処理
|
||||
// ...
|
||||
}
|
||||
|
||||
// using文実行
|
||||
ASTNode::UsingStatement { namespace_name, .. } => {
|
||||
self.execute_using(namespace_name)?;
|
||||
Ok(Box::new(VoidBox::new()))
|
||||
}
|
||||
|
||||
// 他の既存ケース...
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 パフォーマンス特性
|
||||
|
||||
### ⚡ 最適化ポイント
|
||||
|
||||
#### **1. Zero-Allocation関数解決**
|
||||
```rust
|
||||
// ❌ 遅い:毎回文字列生成
|
||||
let qualified = format!("{}.{}", box_name, method_name);
|
||||
|
||||
// ✅ 高速:事前計算済みマップ
|
||||
if let Some(func) = stdlib.flat_functions.get(&qualified_name) { ... }
|
||||
```
|
||||
|
||||
#### **2. 高速名前解決**
|
||||
```rust
|
||||
// O(1)アクセス:HashMap直接ルックアップ
|
||||
// "string.upper" -> BuiltinFunction
|
||||
```
|
||||
|
||||
#### **3. 既存Box実装活用**
|
||||
```rust
|
||||
// 既存の最適化済みStringBox.split()を直接使用
|
||||
string_box.split(separator) // 新規実装不要
|
||||
```
|
||||
|
||||
## 🧪 テストカバレッジ
|
||||
|
||||
### Phase 0必須テスト
|
||||
|
||||
#### **基本機能テスト**
|
||||
```nyash
|
||||
# test_builtin_stdlib_basic.hako
|
||||
using nyashstd
|
||||
|
||||
# 文字列操作
|
||||
assert(string.upper("hello") == "HELLO")
|
||||
assert(string.lower("WORLD") == "world")
|
||||
assert(string.split("a,b,c", ",").length() == 3)
|
||||
|
||||
# 数学関数
|
||||
assert(math.sin(0) == 0)
|
||||
assert(math.cos(0) == 1)
|
||||
|
||||
# 配列操作
|
||||
local arr = [1, 2, 3]
|
||||
assert(array.length(arr) == 3)
|
||||
assert(array.get(arr, 1) == 2)
|
||||
```
|
||||
|
||||
#### **エラーハンドリング**
|
||||
```nyash
|
||||
# test_builtin_stdlib_errors.hako
|
||||
using nyashstd
|
||||
|
||||
# 引数数エラー
|
||||
try {
|
||||
string.upper("hello", "extra") # 2引数でエラー
|
||||
assert(false, "Should have thrown error")
|
||||
} catch e {
|
||||
assert(e.contains("takes exactly 1 argument"))
|
||||
}
|
||||
|
||||
# 未定義名前空間
|
||||
try {
|
||||
using nonexistent
|
||||
assert(false, "Should have thrown error")
|
||||
} catch e {
|
||||
assert(e.contains("UndefinedNamespace"))
|
||||
}
|
||||
```
|
||||
|
||||
#### **IDE補完サポート**
|
||||
```rust
|
||||
// テスト:補完候補取得
|
||||
let methods = stdlib.get_available_methods("nyashstd", "string");
|
||||
assert!(methods.unwrap().contains(&"upper".to_string()));
|
||||
assert!(methods.unwrap().contains(&"lower".to_string()));
|
||||
```
|
||||
|
||||
## 🎯 実装順序
|
||||
|
||||
### 🚨 Critical(即時実装)
|
||||
1. **BuiltinStdlib基盤** - src/stdlib/builtin.rs作成
|
||||
2. **SharedState統合** - builtin_stdlibフィールド追加
|
||||
3. **using文パーサー** - ASTNode::UsingStatement
|
||||
|
||||
### ⚡ High(今週中)
|
||||
4. **string関数4種** - upper, lower, split, join
|
||||
5. **基本テスト** - using nyashstd動作確認
|
||||
6. **エラーハンドリング** - 適切なエラーメッセージ
|
||||
|
||||
### 📝 Medium(来週)
|
||||
7. **math関数5種** - sin, cos, sqrt, floor, random
|
||||
8. **array関数4種** - length, get, push, slice
|
||||
9. **io関数3種** - print, println, debug
|
||||
|
||||
---
|
||||
|
||||
**⚡ この高性能アーキテクチャで、複雑なファイル依存関係なしに即座に実用的なnamespace/usingが実現できるにゃ!🚀**
|
||||
@ -1,394 +0,0 @@
|
||||
# nyash.linkシステム使用例
|
||||
|
||||
## 🎯 基本的な使用例
|
||||
|
||||
### 📁 プロジェクト構造例
|
||||
```
|
||||
my-awesome-app/
|
||||
├── nyash.link # 依存関係定義
|
||||
├── src/
|
||||
│ ├── main.hako # メインファイル
|
||||
│ ├── models/
|
||||
│ │ └── user.hako # ユーザーモデル
|
||||
│ └── utils/
|
||||
│ └── helpers.hako # ヘルパー関数
|
||||
├── libs/
|
||||
│ └── custom_lib.hako # カスタムライブラリ
|
||||
└── stdlib/
|
||||
└── nyashstd.hako # 標準ライブラリ
|
||||
```
|
||||
|
||||
### 📋 nyash.linkファイル例
|
||||
```toml
|
||||
[project]
|
||||
name = "my-awesome-app"
|
||||
version = "1.0.0"
|
||||
description = "Everything is Box philosophy in action!"
|
||||
|
||||
[dependencies]
|
||||
# 標準ライブラリ
|
||||
nyashstd = { path = "./stdlib/nyashstd.hako" }
|
||||
|
||||
# プロジェクト内モジュール
|
||||
user_model = { path = "./src/models/user.hako" }
|
||||
helpers = { path = "./src/utils/helpers.hako" }
|
||||
|
||||
# カスタムライブラリ
|
||||
custom_lib = { path = "./libs/custom_lib.hako" }
|
||||
|
||||
[search_paths]
|
||||
stdlib = "./stdlib/"
|
||||
src = "./src/"
|
||||
libs = "./libs/"
|
||||
|
||||
[build]
|
||||
entry_point = "./src/main.hako"
|
||||
```
|
||||
|
||||
## 🌟 実用的なコード例
|
||||
|
||||
### 1. 基本的なusing使用
|
||||
```nyash
|
||||
# ===== src/main.hako =====
|
||||
using nyashstd
|
||||
using helpers
|
||||
|
||||
static box Main {
|
||||
init { console }
|
||||
|
||||
main() {
|
||||
me.console = new ConsoleBox()
|
||||
|
||||
# 標準ライブラリ使用
|
||||
local text = "hello world"
|
||||
local upper_text = string.upper(text) # nyashstd.string.upper
|
||||
me.console.log("Upper: " + upper_text)
|
||||
|
||||
# ヘルパー関数使用
|
||||
local processed = helpers.process_data("sample data")
|
||||
me.console.log("Processed: " + processed)
|
||||
|
||||
# 数学関数
|
||||
local result = math.sin(3.14159)
|
||||
me.console.log("Sin: " + result.toString())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 標準ライブラリ定義例
|
||||
```nyash
|
||||
# ===== stdlib/nyashstd.hako =====
|
||||
namespace nyashstd {
|
||||
static box string {
|
||||
static upper(str) {
|
||||
local string_box = new StringBox(str)
|
||||
return string_box.upper()
|
||||
}
|
||||
|
||||
static lower(str) {
|
||||
local string_box = new StringBox(str)
|
||||
return string_box.lower()
|
||||
}
|
||||
|
||||
static split(str, separator) {
|
||||
local string_box = new StringBox(str)
|
||||
return string_box.split(separator)
|
||||
}
|
||||
|
||||
static join(array, separator) {
|
||||
local sep_box = new StringBox(separator)
|
||||
return sep_box.join(array)
|
||||
}
|
||||
}
|
||||
|
||||
static box math {
|
||||
static sin(x) {
|
||||
local math_box = new MathBox()
|
||||
return math_box.sin(x)
|
||||
}
|
||||
|
||||
static cos(x) {
|
||||
local math_box = new MathBox()
|
||||
return math_box.cos(x)
|
||||
}
|
||||
|
||||
static random() {
|
||||
local random_box = new RandomBox()
|
||||
return random_box.nextFloat()
|
||||
}
|
||||
|
||||
static floor(x) {
|
||||
local math_box = new MathBox()
|
||||
return math_box.floor(x)
|
||||
}
|
||||
}
|
||||
|
||||
static box io {
|
||||
static read_file(path) {
|
||||
local file_box = new FileBox()
|
||||
return file_box.read(path)
|
||||
}
|
||||
|
||||
static write_file(path, content) {
|
||||
local file_box = new FileBox()
|
||||
return file_box.write(path, content)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. ヘルパーモジュール例
|
||||
```nyash
|
||||
# ===== src/utils/helpers.hako =====
|
||||
using nyashstd
|
||||
|
||||
static function process_data(data) {
|
||||
# データ処理のヘルパー
|
||||
local trimmed = string.trim(data)
|
||||
local upper = string.upper(trimmed)
|
||||
return "PROCESSED: " + upper
|
||||
}
|
||||
|
||||
static function calculate_score(points, multiplier) {
|
||||
local result = points * multiplier
|
||||
return math.floor(result)
|
||||
}
|
||||
|
||||
static function format_user_name(first, last) {
|
||||
return string.upper(first) + " " + string.upper(last)
|
||||
}
|
||||
```
|
||||
|
||||
### 4. モデル定義例
|
||||
```nyash
|
||||
# ===== src/models/user.hako =====
|
||||
using nyashstd
|
||||
using helpers
|
||||
|
||||
box User {
|
||||
init { name, email, score }
|
||||
|
||||
birth(user_name, user_email) {
|
||||
me.name = user_name
|
||||
me.email = user_email
|
||||
me.score = 0
|
||||
}
|
||||
|
||||
add_points(points) {
|
||||
me.score = me.score + points
|
||||
return me.score
|
||||
}
|
||||
|
||||
get_formatted_name() {
|
||||
local parts = string.split(me.name, " ")
|
||||
if parts.length() >= 2 {
|
||||
return helpers.format_user_name(parts.get(0), parts.get(1))
|
||||
} else {
|
||||
return string.upper(me.name)
|
||||
}
|
||||
}
|
||||
|
||||
save_to_file() {
|
||||
local data = "User: " + me.name + ", Email: " + me.email + ", Score: " + me.score.toString()
|
||||
local filename = "user_" + string.lower(me.name) + ".txt"
|
||||
io.write_file(filename, data)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🎮 実用アプリケーション例
|
||||
|
||||
### 1. シンプルなWebサーバー
|
||||
```nyash
|
||||
# ===== web_server.hako =====
|
||||
using nyashstd
|
||||
using custom_lib
|
||||
|
||||
static box WebServer {
|
||||
init { server, port }
|
||||
|
||||
birth(server_port) {
|
||||
me.port = server_port
|
||||
me.server = new HttpServerBox()
|
||||
}
|
||||
|
||||
start() {
|
||||
me.server.bind("localhost", me.port)
|
||||
|
||||
me.server.on("request", me.handle_request)
|
||||
|
||||
local console = new ConsoleBox()
|
||||
console.log("Server started on port " + me.port.toString())
|
||||
|
||||
me.server.listen()
|
||||
}
|
||||
|
||||
handle_request(request, response) {
|
||||
local url = request.getUrl()
|
||||
|
||||
if url == "/" {
|
||||
local html = io.read_file("./public/index.html")
|
||||
response.setStatus(200)
|
||||
response.setHeader("Content-Type", "text/html")
|
||||
response.send(html)
|
||||
} else {
|
||||
response.setStatus(404)
|
||||
response.send("Not Found")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# メイン実行
|
||||
local server = new WebServer(3000)
|
||||
server.start()
|
||||
```
|
||||
|
||||
### 2. データ処理パイプライン
|
||||
```nyash
|
||||
# ===== data_processor.hako =====
|
||||
using nyashstd
|
||||
using helpers
|
||||
|
||||
static box DataProcessor {
|
||||
init { input_file, output_file }
|
||||
|
||||
birth(input_path, output_path) {
|
||||
me.input_file = input_path
|
||||
me.output_file = output_path
|
||||
}
|
||||
|
||||
process() {
|
||||
# データ読み込み
|
||||
local raw_data = io.read_file(me.input_file)
|
||||
local lines = string.split(raw_data, "\n")
|
||||
|
||||
# 処理済みデータ配列
|
||||
local processed_lines = new ArrayBox()
|
||||
|
||||
# 各行を処理
|
||||
local i = 0
|
||||
loop(i < lines.length()) {
|
||||
local line = lines.get(i)
|
||||
local processed = helpers.process_data(line)
|
||||
processed_lines.push(processed)
|
||||
i = i + 1
|
||||
}
|
||||
|
||||
# 結果をファイルに保存
|
||||
local result = string.join(processed_lines, "\n")
|
||||
io.write_file(me.output_file, result)
|
||||
|
||||
return processed_lines.length()
|
||||
}
|
||||
}
|
||||
|
||||
# メイン処理
|
||||
local processor = new DataProcessor("input.txt", "output.txt")
|
||||
local count = processor.process()
|
||||
|
||||
local console = new ConsoleBox()
|
||||
console.log("Processed " + count.toString() + " lines")
|
||||
```
|
||||
|
||||
## 🔧 高度な使用パターン
|
||||
|
||||
### 1. 条件付きモジュール読み込み(将来拡張)
|
||||
```nyash
|
||||
# 開発環境では詳細ログ、本番環境ではシンプルログ
|
||||
using nyashstd
|
||||
|
||||
static function get_logger() {
|
||||
local env = os.get_env("NYASH_ENV")
|
||||
|
||||
if env == "development" {
|
||||
using dev_logger
|
||||
return new dev_logger.DetailLogger()
|
||||
} else {
|
||||
using prod_logger
|
||||
return new prod_logger.SimpleLogger()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. エイリアス使用例(将来拡張)
|
||||
```nyash
|
||||
# 長い名前空間のエイリアス
|
||||
using very.long.namespace.name as short
|
||||
|
||||
local result = short.helper_function("data")
|
||||
|
||||
# 複数の類似ライブラリ
|
||||
using json_v1 as json1
|
||||
using json_v2 as json2
|
||||
|
||||
local data1 = json1.parse(input)
|
||||
local data2 = json2.parse(input)
|
||||
```
|
||||
|
||||
### 3. 部分インポート(将来拡張)
|
||||
```nyash
|
||||
# 名前空間全体ではなく特定機能のみ
|
||||
using nyashstd.string
|
||||
using nyashstd.math
|
||||
|
||||
# これで直接呼び出せる
|
||||
local result = upper("hello") # string.upper不要
|
||||
local sin_val = sin(3.14) # math.sin不要
|
||||
```
|
||||
|
||||
## 📊 移行例:既存includeからusingへ
|
||||
|
||||
### Before(現在のinclude使用)
|
||||
```nyash
|
||||
# ===== 既存のtext_adventure例 =====
|
||||
include "text_adventure/items.hako"
|
||||
include "text_adventure/rooms.hako"
|
||||
|
||||
# アイテム作成
|
||||
local sword = new Weapon("Sword", 10)
|
||||
```
|
||||
|
||||
### After(新しいusing使用)
|
||||
```nyash
|
||||
# ===== nyash.link =====
|
||||
[dependencies]
|
||||
game_items = { path = "./text_adventure/items.hako" }
|
||||
game_rooms = { path = "./text_adventure/rooms.hako" }
|
||||
|
||||
# ===== main.hako =====
|
||||
using game_items
|
||||
using game_rooms
|
||||
|
||||
# アイテム作成(名前空間経由)
|
||||
local sword = game_items.create_weapon("Sword", 10)
|
||||
```
|
||||
|
||||
## 🎉 期待される開発体験
|
||||
|
||||
### IDE補完の改善
|
||||
```nyash
|
||||
using nyashstd
|
||||
|
||||
# "st" と入力すると...
|
||||
st → string (補完候補)
|
||||
|
||||
# "string." と入力すると...
|
||||
string. → upper, lower, split, join, trim, ... (全メソッド表示)
|
||||
```
|
||||
|
||||
### エラーメッセージの改善
|
||||
```nyash
|
||||
using nyashstd
|
||||
|
||||
# 間違った呼び出し
|
||||
local result = string.uppper("hello") # typo
|
||||
|
||||
# エラー:
|
||||
# Error: Method 'uppper' not found in nyashstd.string
|
||||
# Did you mean: 'upper'?
|
||||
# Available methods: upper, lower, split, join, trim
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**🌟 これらの例でnyash.linkシステムの実用性と美しさが伝わるにゃ!🐱**
|
||||
@ -1,406 +0,0 @@
|
||||
# 最終実装戦略:標準関数優先namespace/usingシステム
|
||||
|
||||
## 🎯 実装戦略まとめ
|
||||
|
||||
### 📋 設計完了項目
|
||||
- ✅ **基本戦略**: nyash.link前の段階的実装
|
||||
- ✅ **アーキテクチャ**: SharedState統合による高性能設計
|
||||
- ✅ **標準関数**: 組み込みnyashstd名前空間
|
||||
- ✅ **実装順序**: Critical → High → Medium
|
||||
|
||||
### 🚀 最終実装ロードマップ
|
||||
|
||||
## Phase 0: 組み込みnyashstd基盤(1-2週間)
|
||||
|
||||
### 🚨 Critical実装(即時)
|
||||
|
||||
#### **1. トークナイザー拡張**
|
||||
```rust
|
||||
// src/tokenizer.rs
|
||||
pub enum TokenType {
|
||||
// 既存...
|
||||
USING, // using キーワード追加
|
||||
}
|
||||
|
||||
// キーワード認識
|
||||
fn tokenize_keyword(word: &str) -> TokenType {
|
||||
match word {
|
||||
// 既存...
|
||||
"using" => TokenType::USING,
|
||||
_ => TokenType::IDENTIFIER(word.to_string()),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **2. AST最小拡張**
|
||||
```rust
|
||||
// src/ast.rs
|
||||
pub enum ASTNode {
|
||||
// 既存...
|
||||
UsingStatement {
|
||||
namespace_name: String, // Phase 0: "nyashstd"のみ
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
#### **3. BuiltinStdlib基盤**
|
||||
```rust
|
||||
// 新ファイル: src/stdlib/mod.rs
|
||||
pub mod builtin;
|
||||
pub use builtin::*;
|
||||
|
||||
// 新ファイル: src/stdlib/builtin.rs
|
||||
// (前回設計したBuiltinStdlib実装)
|
||||
```
|
||||
|
||||
#### **4. SharedState統合**
|
||||
```rust
|
||||
// src/interpreter/core.rs
|
||||
#[derive(Clone)]
|
||||
pub struct SharedState {
|
||||
// 既存フィールド...
|
||||
pub builtin_stdlib: Arc<BuiltinStdlib>,
|
||||
pub using_imports: Arc<RwLock<HashMap<String, UsingContext>>>,
|
||||
}
|
||||
|
||||
impl SharedState {
|
||||
pub fn new() -> Self {
|
||||
SharedState {
|
||||
// 既存初期化...
|
||||
builtin_stdlib: Arc::new(BuiltinStdlib::new()),
|
||||
using_imports: Arc::new(RwLock::new(HashMap::new())),
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ⚡ High実装(今週中)
|
||||
|
||||
#### **5. using文パーサー**
|
||||
```rust
|
||||
// src/parser/statements.rs
|
||||
impl NyashParser {
|
||||
pub fn parse_statement(&mut self) -> Result<ASTNode, ParseError> {
|
||||
match &self.current_token().token_type {
|
||||
// 既存ケース...
|
||||
TokenType::USING => self.parse_using(),
|
||||
// 他の既存ケース...
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_using(&mut self) -> Result<ASTNode, ParseError> {
|
||||
let start_span = self.current_token().span.clone();
|
||||
self.advance(); // consume 'using'
|
||||
|
||||
if let TokenType::IDENTIFIER(namespace_name) = &self.current_token().token_type {
|
||||
let name = namespace_name.clone();
|
||||
self.advance();
|
||||
|
||||
// Phase 0制限:nyashstdのみ許可
|
||||
if name != "nyashstd" {
|
||||
return Err(ParseError::UnsupportedFeature(
|
||||
format!("Only 'nyashstd' namespace is supported in Phase 0, got '{}'", name)
|
||||
));
|
||||
}
|
||||
|
||||
Ok(ASTNode::UsingStatement {
|
||||
namespace_name: name,
|
||||
span: start_span,
|
||||
})
|
||||
} else {
|
||||
Err(ParseError::ExpectedIdentifier(
|
||||
"Expected namespace name after 'using'".to_string()
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **6. 基本string関数実装**
|
||||
```rust
|
||||
// src/stdlib/builtin.rs拡張
|
||||
impl BuiltinStdlib {
|
||||
fn register_string_functions(&mut self) {
|
||||
// string.upper
|
||||
self.register_function("string.upper", BuiltinFunction {
|
||||
namespace: "nyashstd",
|
||||
box_name: "string",
|
||||
method_name: "upper",
|
||||
implementation: |args| {
|
||||
if args.len() != 1 {
|
||||
return Err(RuntimeError::InvalidArguments(
|
||||
"string.upper() takes exactly 1 argument".to_string()
|
||||
));
|
||||
}
|
||||
|
||||
let input = &args[0].to_string_box().value;
|
||||
let result = StringBox::new(&input.to_uppercase());
|
||||
Ok(Box::new(result))
|
||||
},
|
||||
arg_count: Some(1),
|
||||
description: "Convert string to uppercase",
|
||||
});
|
||||
|
||||
// string.lower
|
||||
self.register_function("string.lower", BuiltinFunction {
|
||||
namespace: "nyashstd",
|
||||
box_name: "string",
|
||||
method_name: "lower",
|
||||
implementation: |args| {
|
||||
if args.len() != 1 {
|
||||
return Err(RuntimeError::InvalidArguments(
|
||||
"string.lower() takes exactly 1 argument".to_string()
|
||||
));
|
||||
}
|
||||
|
||||
let input = &args[0].to_string_box().value;
|
||||
let result = StringBox::new(&input.to_lowercase());
|
||||
Ok(Box::new(result))
|
||||
},
|
||||
arg_count: Some(1),
|
||||
description: "Convert string to lowercase",
|
||||
});
|
||||
|
||||
// string.split
|
||||
self.register_function("string.split", BuiltinFunction {
|
||||
namespace: "nyashstd",
|
||||
box_name: "string",
|
||||
method_name: "split",
|
||||
implementation: |args| {
|
||||
if args.len() != 2 {
|
||||
return Err(RuntimeError::InvalidArguments(
|
||||
"string.split() takes exactly 2 arguments".to_string()
|
||||
));
|
||||
}
|
||||
|
||||
let string_box = StringBox::new(&args[0].to_string_box().value);
|
||||
let separator = &args[1].to_string_box().value;
|
||||
string_box.split(separator)
|
||||
},
|
||||
arg_count: Some(2),
|
||||
description: "Split string by separator",
|
||||
});
|
||||
|
||||
// string.join
|
||||
self.register_function("string.join", BuiltinFunction {
|
||||
namespace: "nyashstd",
|
||||
box_name: "string",
|
||||
method_name: "join",
|
||||
implementation: |args| {
|
||||
if args.len() != 2 {
|
||||
return Err(RuntimeError::InvalidArguments(
|
||||
"string.join() takes exactly 2 arguments".to_string()
|
||||
));
|
||||
}
|
||||
|
||||
let array_arg = &args[0];
|
||||
let separator = &args[1].to_string_box().value;
|
||||
let separator_box = StringBox::new(separator);
|
||||
separator_box.join(array_arg.clone())
|
||||
},
|
||||
arg_count: Some(2),
|
||||
description: "Join array elements with separator",
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **7. インタープリター統合**
|
||||
```rust
|
||||
// src/interpreter/expressions.rs
|
||||
impl NyashInterpreter {
|
||||
pub fn execute_expression(&mut self, node: &ASTNode) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
match node {
|
||||
// using文処理
|
||||
ASTNode::UsingStatement { namespace_name, .. } => {
|
||||
self.execute_using(namespace_name)?;
|
||||
Ok(Box::new(VoidBox::new()))
|
||||
}
|
||||
|
||||
// メソッド呼び出し処理拡張
|
||||
ASTNode::MethodCall { object, method, args, .. } => {
|
||||
// 組み込み関数チェック
|
||||
if let ASTNode::Variable { name: box_name, .. } = object.as_ref() {
|
||||
let path = vec![box_name.clone(), method.clone()];
|
||||
if let Some(qualified_name) = self.resolve_qualified_call(&path) {
|
||||
let evaluated_args = self.evaluate_arguments(args)?;
|
||||
return self.call_builtin_function(&qualified_name, evaluated_args);
|
||||
}
|
||||
}
|
||||
|
||||
// 既存のメソッド呼び出し処理
|
||||
// ...
|
||||
}
|
||||
|
||||
// 既存の他のケース...
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 📝 Medium実装(来週)
|
||||
|
||||
#### **8. math関数実装**
|
||||
```rust
|
||||
// math.sin, cos, sqrt, floor, random
|
||||
```
|
||||
|
||||
#### **9. array関数実装**
|
||||
```rust
|
||||
// array.length, get, push, slice
|
||||
```
|
||||
|
||||
#### **10. io関数実装**
|
||||
```rust
|
||||
// io.print, println, debug
|
||||
```
|
||||
|
||||
## Phase 1: 拡張機能(2-3週間後)
|
||||
|
||||
### 🌟 完全修飾名対応
|
||||
```nyash
|
||||
# using不要でも使える
|
||||
nyashstd.string.upper("hello")
|
||||
nyashstd.math.sin(3.14)
|
||||
```
|
||||
|
||||
#### **実装**
|
||||
```rust
|
||||
// ASTNode::QualifiedCall追加
|
||||
ASTNode::QualifiedCall {
|
||||
path: Vec<String>, // ["nyashstd", "string", "upper"]
|
||||
args: Vec<ASTNode>,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
// パーサーで "identifier.identifier.identifier()" 構文解析
|
||||
```
|
||||
|
||||
### 🔧 エラーハンドリング強化
|
||||
```rust
|
||||
// より詳細なエラーメッセージ
|
||||
RuntimeError::UndefinedBuiltinMethod {
|
||||
namespace: String,
|
||||
box_name: String,
|
||||
method_name: String,
|
||||
available_methods: Vec<String>, // "Did you mean: ..."
|
||||
span: Span,
|
||||
}
|
||||
```
|
||||
|
||||
### 📊 IDE補完サポート
|
||||
```rust
|
||||
// Language Server連携用API
|
||||
impl BuiltinStdlib {
|
||||
pub fn get_completion_candidates(&self, prefix: &str) -> Vec<CompletionItem> {
|
||||
// "ny" -> ["nyashstd"]
|
||||
// "nyashstd." -> ["string", "math", "array", "io"]
|
||||
// "nyashstd.string." -> ["upper", "lower", "split", "join"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Phase 2: nyash.link準備(1ヶ月後)
|
||||
|
||||
### 🔗 外部モジュール対応基盤
|
||||
```rust
|
||||
// ModuleResolver拡張
|
||||
pub enum NamespaceSource {
|
||||
Builtin(Arc<BuiltinStdlib>), // 組み込み
|
||||
External(PathBuf), // nyash.linkで管理
|
||||
}
|
||||
|
||||
// NamespaceRegistry統合
|
||||
pub struct NamespaceRegistry {
|
||||
builtin: Arc<BuiltinStdlib>,
|
||||
external: HashMap<String, ExternalModule>,
|
||||
}
|
||||
```
|
||||
|
||||
### 📁 nyash.link対応
|
||||
```toml
|
||||
[dependencies]
|
||||
mylib = { path = "./mylib.hako" }
|
||||
|
||||
# using mylib # Phase 2で対応
|
||||
```
|
||||
|
||||
## 🧪 段階的テスト戦略
|
||||
|
||||
### Phase 0テスト
|
||||
```nyash
|
||||
# test_phase0_basic.hako
|
||||
using nyashstd
|
||||
|
||||
# 基本動作
|
||||
assert(string.upper("hello") == "HELLO")
|
||||
assert(string.lower("WORLD") == "world")
|
||||
|
||||
# エラー処理
|
||||
try {
|
||||
using unknown_namespace
|
||||
} catch e {
|
||||
assert(e.contains("nyashstd"))
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 1テスト
|
||||
```nyash
|
||||
# test_phase1_qualified.hako
|
||||
# using不要のテスト
|
||||
assert(nyashstd.string.upper("hello") == "HELLO")
|
||||
assert(nyashstd.math.sin(0) == 0)
|
||||
```
|
||||
|
||||
### Phase 2テスト
|
||||
```nyash
|
||||
# test_phase2_external.hako
|
||||
using mylib
|
||||
|
||||
assert(mylib.custom.process("data") == "processed: data")
|
||||
```
|
||||
|
||||
## 📊 実装マイルストーン
|
||||
|
||||
### ✅ Phase 0完了条件
|
||||
- [ ] USINGトークン認識
|
||||
- [ ] using nyashstd構文解析
|
||||
- [ ] 組み込みstring関数4種動作
|
||||
- [ ] 基本テスト全通過
|
||||
- [ ] エラーハンドリング適切
|
||||
|
||||
### ✅ Phase 1完了条件
|
||||
- [ ] 完全修飾名 nyashstd.string.upper() 動作
|
||||
- [ ] math/array/io関数実装
|
||||
- [ ] IDE補完候補API実装
|
||||
- [ ] 詳細エラーメッセージ
|
||||
|
||||
### ✅ Phase 2完了条件
|
||||
- [ ] 外部モジュール基盤実装
|
||||
- [ ] nyash.link基本対応
|
||||
- [ ] 依存関係解決機能
|
||||
- [ ] 全機能統合テスト
|
||||
|
||||
## 🔥 即座に開始すべき実装
|
||||
|
||||
### 今日やること
|
||||
1. **src/stdlib/mod.rs作成** - モジュール基盤
|
||||
2. **TokenType::USING追加** - トークナイザー拡張
|
||||
3. **BuiltinStdlib::new()実装** - 空の基盤作成
|
||||
|
||||
### 今週やること
|
||||
4. **using文パーサー実装** - 基本構文解析
|
||||
5. **string.upper()実装** - 最初の関数
|
||||
6. **基本テスト作成** - 動作確認
|
||||
|
||||
### 来週やること
|
||||
7. **string関数完成** - lower, split, join
|
||||
8. **math関数開始** - sin, cos, sqrt
|
||||
9. **IDE補完設計** - Language Server準備
|
||||
|
||||
---
|
||||
|
||||
**🎯 この段階的戦略で、複雑なnyash.linkなしに即座に実用的なnamespace/usingシステムが実現できるにゃ!**
|
||||
|
||||
**🚀 Phase 0実装を今すぐ開始して、Nyashをモダンなプログラミング言語に進化させよう!🐱✨**
|
||||
@ -1,471 +0,0 @@
|
||||
# nyash.linkシステム実装計画
|
||||
|
||||
## 🎯 実装戦略
|
||||
|
||||
### 📊 現状確認
|
||||
- ✅ **include**: 限定的使用(text_adventure例のみ)→廃止OK
|
||||
- ✅ **using**: 未実装→完全新規作成
|
||||
- ✅ **namespace**: 設計完了→実装のみ
|
||||
- ✅ **Gemini推奨**: 技術的妥当性確認済み
|
||||
|
||||
## 📋 段階的実装ロードマップ
|
||||
|
||||
### 🚀 **Phase 1: 基盤構築(1-2週間)**
|
||||
|
||||
#### 1.1 トークナイザー拡張
|
||||
```rust
|
||||
// src/tokenizer.rs
|
||||
pub enum TokenType {
|
||||
// 既存...
|
||||
USING, // using キーワード
|
||||
NAMESPACE, // namespace キーワード
|
||||
AS, // as キーワード(将来のエイリアス用)
|
||||
}
|
||||
|
||||
// キーワード認識追加
|
||||
fn tokenize_identifier(input: &str) -> TokenType {
|
||||
match input {
|
||||
// 既存...
|
||||
"using" => TokenType::USING,
|
||||
"namespace" => TokenType::NAMESPACE,
|
||||
"as" => TokenType::AS,
|
||||
_ => TokenType::IDENTIFIER(input.to_string()),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.2 AST拡張
|
||||
```rust
|
||||
// src/ast.rs
|
||||
pub enum ASTNode {
|
||||
// 既存...
|
||||
UsingStatement {
|
||||
module_path: Vec<String>, // ["nyashstd"] or ["mylib"]
|
||||
alias: Option<String>, // using mylib as lib
|
||||
span: Span,
|
||||
},
|
||||
NamespaceDeclaration {
|
||||
name: String,
|
||||
body: Vec<ASTNode>,
|
||||
span: Span,
|
||||
},
|
||||
QualifiedCall {
|
||||
path: Vec<String>, // ["nyashstd", "string", "upper"]
|
||||
args: Vec<ASTNode>,
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.3 パーサー基本実装
|
||||
```rust
|
||||
// src/parser/statements.rs
|
||||
impl NyashParser {
|
||||
pub fn parse_using(&mut self) -> Result<ASTNode, ParseError> {
|
||||
self.advance(); // consume 'using'
|
||||
|
||||
let module_path = self.parse_module_path()?;
|
||||
// using mylib → ["mylib"]
|
||||
// using nyashstd.string → ["nyashstd", "string"]
|
||||
|
||||
Ok(ASTNode::UsingStatement {
|
||||
module_path,
|
||||
alias: None, // Phase 1では未サポート
|
||||
span: self.current_span(),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_module_path(&mut self) -> Result<Vec<String>, ParseError> {
|
||||
let mut path = vec![];
|
||||
|
||||
// 最初の識別子
|
||||
if let TokenType::IDENTIFIER(name) = &self.current_token().token_type {
|
||||
path.push(name.clone());
|
||||
self.advance();
|
||||
} else {
|
||||
return Err(ParseError::ExpectedIdentifier);
|
||||
}
|
||||
|
||||
// ドット区切りで追加パス(将来拡張)
|
||||
// using nyashstd.string のような構文
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ⚡ **Phase 2: nyash.link基盤(2-3週間)**
|
||||
|
||||
#### 2.1 nyash.linkパーサー
|
||||
```rust
|
||||
// 新ファイル: src/link_file.rs
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct NyashLink {
|
||||
pub project: Option<ProjectInfo>,
|
||||
pub dependencies: HashMap<String, Dependency>,
|
||||
pub search_paths: Option<HashMap<String, String>>,
|
||||
pub build: Option<BuildConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct ProjectInfo {
|
||||
pub name: String,
|
||||
pub version: String,
|
||||
pub description: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum Dependency {
|
||||
Path { path: String },
|
||||
Stdlib { stdlib: bool },
|
||||
Registry { version: String, registry: String },
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct BuildConfig {
|
||||
pub entry_point: Option<String>,
|
||||
}
|
||||
|
||||
impl NyashLink {
|
||||
pub fn from_file(path: &Path) -> Result<Self, LinkError> {
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
let link: NyashLink = toml::from_str(&content)?;
|
||||
Ok(link)
|
||||
}
|
||||
|
||||
pub fn resolve_dependency(&self, name: &str) -> Option<PathBuf> {
|
||||
if let Some(dep) = self.dependencies.get(name) {
|
||||
match dep {
|
||||
Dependency::Path { path } => Some(PathBuf::from(path)),
|
||||
Dependency::Stdlib { .. } => {
|
||||
// 標準ライブラリパス解決ロジック
|
||||
self.resolve_stdlib_path(name)
|
||||
}
|
||||
_ => None, // Phase 2では未サポート
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2 依存関係解決エンジン
|
||||
```rust
|
||||
// 新ファイル: src/module_resolver.rs
|
||||
pub struct ModuleResolver {
|
||||
nyash_link: NyashLink,
|
||||
loaded_modules: HashMap<String, Arc<ParsedModule>>,
|
||||
loading_stack: Vec<String>, // 循環依存検出用
|
||||
}
|
||||
|
||||
impl ModuleResolver {
|
||||
pub fn new(link_path: &Path) -> Result<Self, ResolverError> {
|
||||
let nyash_link = NyashLink::from_file(link_path)?;
|
||||
Ok(ModuleResolver {
|
||||
nyash_link,
|
||||
loaded_modules: HashMap::new(),
|
||||
loading_stack: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn resolve_using(&mut self, module_name: &str) -> Result<Arc<ParsedModule>, ResolverError> {
|
||||
// 既にロード済みかチェック
|
||||
if let Some(module) = self.loaded_modules.get(module_name) {
|
||||
return Ok(module.clone());
|
||||
}
|
||||
|
||||
// 循環依存チェック
|
||||
if self.loading_stack.contains(&module_name.to_string()) {
|
||||
return Err(ResolverError::CircularDependency(
|
||||
self.loading_stack.clone()
|
||||
));
|
||||
}
|
||||
|
||||
// ファイルパス解決
|
||||
let file_path = self.hako_link.resolve_dependency(module_name)
|
||||
.ok_or(ResolverError::ModuleNotFound(module_name.to_string()))?;
|
||||
|
||||
// 再帰的読み込み防止
|
||||
self.loading_stack.push(module_name.to_string());
|
||||
|
||||
// ファイル読み込み・パース
|
||||
let content = std::fs::read_to_string(&file_path)?;
|
||||
let ast = NyashParser::parse_from_string(&content)?;
|
||||
|
||||
// モジュール作成
|
||||
let module = Arc::new(ParsedModule {
|
||||
name: module_name.to_string(),
|
||||
file_path,
|
||||
ast,
|
||||
exports: self.extract_exports(&ast)?,
|
||||
});
|
||||
|
||||
// キャッシュに保存
|
||||
self.loaded_modules.insert(module_name.to_string(), module.clone());
|
||||
self.loading_stack.pop();
|
||||
|
||||
Ok(module)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 📈 **Phase 3: 名前空間システム(3-4週間)**
|
||||
|
||||
#### 3.1 namespace解析
|
||||
```rust
|
||||
impl NyashParser {
|
||||
pub fn parse_namespace(&mut self) -> Result<ASTNode, ParseError> {
|
||||
self.advance(); // consume 'namespace'
|
||||
|
||||
let name = self.expect_identifier()?;
|
||||
self.expect_token(TokenType::LBRACE)?;
|
||||
|
||||
let mut body = vec![];
|
||||
while !self.check_token(&TokenType::RBRACE) {
|
||||
body.push(self.parse_statement()?);
|
||||
}
|
||||
|
||||
self.expect_token(TokenType::RBRACE)?;
|
||||
|
||||
Ok(ASTNode::NamespaceDeclaration {
|
||||
name,
|
||||
body,
|
||||
span: self.current_span(),
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.2 名前空間レジストリ
|
||||
```rust
|
||||
// 新ファイル: src/namespace_registry.rs
|
||||
pub struct NamespaceRegistry {
|
||||
namespaces: HashMap<String, Namespace>,
|
||||
using_imports: HashMap<String, Vec<String>>, // ファイル別インポート
|
||||
}
|
||||
|
||||
pub struct Namespace {
|
||||
pub name: String,
|
||||
pub static_boxes: HashMap<String, StaticBox>,
|
||||
}
|
||||
|
||||
pub struct StaticBox {
|
||||
pub name: String,
|
||||
pub static_methods: HashMap<String, MethodSignature>,
|
||||
}
|
||||
|
||||
impl NamespaceRegistry {
|
||||
pub fn register_namespace(&mut self, name: String, namespace: Namespace) {
|
||||
self.namespaces.insert(name, namespace);
|
||||
}
|
||||
|
||||
pub fn add_using_import(&mut self, file_id: String, namespace_name: String) {
|
||||
self.using_imports
|
||||
.entry(file_id)
|
||||
.or_insert_with(Vec::new)
|
||||
.push(namespace_name);
|
||||
}
|
||||
|
||||
pub fn resolve_call(&self, file_id: &str, path: &[String]) -> Option<MethodSignature> {
|
||||
// 例: string.upper() → nyashstd.string.upper()
|
||||
if path.len() == 2 {
|
||||
let box_name = &path[0];
|
||||
let method_name = &path[1];
|
||||
|
||||
// usingでインポートされた名前空間を検索
|
||||
if let Some(imports) = self.using_imports.get(file_id) {
|
||||
for namespace_name in imports {
|
||||
if let Some(namespace) = self.namespaces.get(namespace_name) {
|
||||
if let Some(static_box) = namespace.static_boxes.get(box_name) {
|
||||
if let Some(method) = static_box.static_methods.get(method_name) {
|
||||
return Some(method.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 🎯 **Phase 4: インタープリター統合(4-5週間)**
|
||||
|
||||
#### 4.1 using文実行
|
||||
```rust
|
||||
// src/interpreter/core.rs
|
||||
impl NyashInterpreter {
|
||||
pub fn execute_using(&mut self, module_path: &[String]) -> Result<(), RuntimeError> {
|
||||
let module_name = module_path.join(".");
|
||||
|
||||
// モジュール解決・読み込み
|
||||
let module = self.module_resolver.resolve_using(&module_name)?;
|
||||
|
||||
// 名前空間登録
|
||||
if let Some(namespace) = self.extract_namespace_from_module(&module) {
|
||||
self.namespace_registry.register_namespace(module_name.clone(), namespace);
|
||||
self.namespace_registry.add_using_import(
|
||||
self.current_file_id.clone(),
|
||||
module_name
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn extract_namespace_from_module(&self, module: &ParsedModule) -> Option<Namespace> {
|
||||
// ASTからnamespace宣言を探して解析
|
||||
for node in &module.ast {
|
||||
if let ASTNode::NamespaceDeclaration { name, body, .. } = node {
|
||||
return Some(self.build_namespace_from_body(name, body));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.2 qualified call実行
|
||||
```rust
|
||||
impl NyashInterpreter {
|
||||
pub fn execute_qualified_call(&mut self, path: &[String], args: &[ASTNode])
|
||||
-> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
|
||||
// 名前解決
|
||||
if let Some(method_sig) = self.namespace_registry.resolve_call(
|
||||
&self.current_file_id,
|
||||
path
|
||||
) {
|
||||
// 引数評価
|
||||
let evaluated_args = self.evaluate_args(args)?;
|
||||
|
||||
// メソッド実行(既存のBox呼び出しシステム活用)
|
||||
return self.call_static_method(&method_sig, evaluated_args);
|
||||
}
|
||||
|
||||
// 完全修飾名として試行
|
||||
if path.len() >= 3 {
|
||||
// nyashstd.string.upper() の場合
|
||||
let namespace_name = &path[0];
|
||||
let box_name = &path[1];
|
||||
let method_name = &path[2];
|
||||
|
||||
if let Some(namespace) = self.namespace_registry.namespaces.get(namespace_name) {
|
||||
if let Some(static_box) = namespace.static_boxes.get(box_name) {
|
||||
if let Some(method) = static_box.static_methods.get(method_name) {
|
||||
let evaluated_args = self.evaluate_args(args)?;
|
||||
return self.call_static_method(method, evaluated_args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(RuntimeError::UndefinedMethod(path.join(".")))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🧪 テスト戦略
|
||||
|
||||
### Phase 1テスト
|
||||
```nyash
|
||||
# test_basic_using.hako
|
||||
# 基本using文テスト
|
||||
|
||||
# ファイル: mylib.hako
|
||||
static function hello() {
|
||||
return "Hello from mylib!"
|
||||
}
|
||||
|
||||
# ファイル: main.hako
|
||||
using mylib
|
||||
local result = mylib.hello()
|
||||
assert(result == "Hello from mylib!")
|
||||
```
|
||||
|
||||
### Phase 2テスト
|
||||
```nyash
|
||||
# test_nyash_link.hako
|
||||
# nyash.linkファイル連携テスト
|
||||
|
||||
# nyash.link内容:
|
||||
# [dependencies]
|
||||
# mylib = { path = "./mylib.hako" }
|
||||
|
||||
using mylib
|
||||
local result = mylib.process("data")
|
||||
assert(result == "processed: data")
|
||||
```
|
||||
|
||||
### Phase 3テスト
|
||||
```nyash
|
||||
# test_namespace.hako
|
||||
# 名前空間システムテスト
|
||||
|
||||
# nyashstd.hako:
|
||||
# namespace nyashstd {
|
||||
# static box string {
|
||||
# static upper(str) { ... }
|
||||
# }
|
||||
# }
|
||||
|
||||
using nyashstd
|
||||
local result = string.upper("hello")
|
||||
assert(result == "HELLO")
|
||||
|
||||
# 完全修飾名
|
||||
local result2 = nyashstd.string.upper("world")
|
||||
assert(result2 == "WORLD")
|
||||
```
|
||||
|
||||
## 📊 実装マイルストーン
|
||||
|
||||
### ✅ 完了条件
|
||||
|
||||
#### Phase 1
|
||||
- [ ] USING/NAMESPACE トークン認識
|
||||
- [ ] using文AST構築
|
||||
- [ ] 基本パーサーテスト通過
|
||||
|
||||
#### Phase 2
|
||||
- [ ] nyash.linkファイル読み込み
|
||||
- [ ] 依存関係解決
|
||||
- [ ] モジュールキャッシュ機能
|
||||
|
||||
#### Phase 3
|
||||
- [ ] namespace宣言解析
|
||||
- [ ] 名前空間レジストリ動作
|
||||
- [ ] 静的メソッド解決
|
||||
|
||||
#### Phase 4
|
||||
- [ ] インタープリター統合
|
||||
- [ ] qualified call実行
|
||||
- [ ] 全テストケース通過
|
||||
|
||||
## 🔮 将来拡張
|
||||
|
||||
### Phase 5: 高度機能
|
||||
- エイリアス(`using mylib as lib`)
|
||||
- 選択インポート(`using nyashstd.string`)
|
||||
- 動的モジュール読み込み
|
||||
|
||||
### Phase 6: 標準ライブラリ
|
||||
- nyashstd.hako完全実装
|
||||
- string/math/io/http モジュール
|
||||
- ドキュメント生成
|
||||
|
||||
### Phase 7: エコシステム
|
||||
- パッケージレジストリ設計
|
||||
- CLI ツール(nyash init/install)
|
||||
- IDE Language Server連携
|
||||
|
||||
---
|
||||
|
||||
**🎯 この実装計画でnyash.linkシステムを段階的に完成させるにゃ!**
|
||||
@ -1,372 +0,0 @@
|
||||
# なんでもAPI計画:最終統合アーキテクチャ
|
||||
|
||||
## 🌟 革命的ビジョンの実現
|
||||
|
||||
### 📊 統合設計完了状況
|
||||
- ✅ **nyash.link基盤**: 依存関係管理システム設計完了
|
||||
- ✅ **FFI-ABI統合**: BID×MIR×バックエンド統合設計完了
|
||||
- ✅ **usingシステム**: 3種類API統一インポート設計完了
|
||||
- ✅ **実世界例**: ゲーム・データサイエンス・Web・システムプログラミング実証
|
||||
- 🎯 **最終統合**: 全システム統合による革命的開発体験実現
|
||||
|
||||
### 🚀 完成後の開発体験
|
||||
```nyash
|
||||
# === たった一つの構文ですべてが使える ===
|
||||
using nyashstd # 組み込み標準ライブラリ
|
||||
using browser_api # ブラウザAPI(Canvas, DOM, WebAudio...)
|
||||
using system_api # システムAPI(libc, filesystem, network...)
|
||||
using ml_api # 機械学習(TensorFlow, PyTorch, OpenCV...)
|
||||
using game_api # ゲーム開発(SDL, OpenGL, Vulkan...)
|
||||
using mylib # 自作Nyashモジュール
|
||||
|
||||
# 全部同じ記法・同じパフォーマンス・同じエラーハンドリング!
|
||||
string.upper("hello") # 組み込み標準
|
||||
browser.canvas.fillRect("game", 10, 10, 100, 100, "red") # ブラウザAPI
|
||||
system.file.read("/etc/passwd") # システムAPI
|
||||
ml.opencv.loadImage("photo.jpg") # 機械学習API
|
||||
game.sdl.createWindow("Game", 800, 600) # ゲームAPI
|
||||
mylib.processData("input") # 自作モジュール
|
||||
```
|
||||
|
||||
## 🏗️ 最終統合アーキテクチャ
|
||||
|
||||
### 1. 全体システム構成
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ Nyash Code │ │ nyash.link │ │ BID Files │
|
||||
│ │ │ │ │ │
|
||||
│ using browser_api│ │ [dependencies] │ │ browser_api: │
|
||||
│ using system_api │───▶│ browser_api = │───▶│ canvas.yaml │
|
||||
│ using mylib │ │ {bid=...} │ │ dom.yaml │
|
||||
│ canvas.fillRect │ │ system_api = │ │ system_api: │
|
||||
│ file.read │ │ {bid=...} │ │ libc.yaml │
|
||||
│ mylib.process │ │ mylib = {path} │ │ filesystem.yaml│
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│ │ │
|
||||
└────────────────────────┼────────────────────────┘
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ UniversalNamespaceRegistry │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
|
||||
│ │BuiltinStdlib│ │BidDefinition│ │ExternalModules │ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │nyashstd.* │ │browser_api.*│ │mylib.* │ │
|
||||
│ │string.upper │ │canvas.fill* │ │custom functions │ │
|
||||
│ │math.sin │ │dom.events │ │ │ │
|
||||
│ │array.length │ │system.file* │ │ │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ MIR Generation │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
|
||||
│ │BuiltinCall │ │ExternCall │ │ModuleCall │ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │string.upper │ │canvas.fill* │ │mylib.process │ │
|
||||
│ │effect:pure │ │effect:io │ │effect:io │ │
|
||||
│ │optimize:yes │ │gpu_accel:yes│ │ │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Backend Execution │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
|
||||
│ │ VM │ │ WASM │ │ AOT │ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │Native Impl │ │RuntimeImport│ │LLVM ExternFunc │ │
|
||||
│ │Stub Calls │ │Auto-generated│ │Native Libraries │ │
|
||||
│ │ │ │from BID │ │ │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2. nyash.link統合仕様(最終版)
|
||||
```toml
|
||||
# nyash.link - 全API統一管理設定
|
||||
[project]
|
||||
name = "ultimate-nyash-app"
|
||||
version = "2.0.0"
|
||||
description = "Everything is accessible through unified APIs"
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
# === 組み込み標準ライブラリ ===
|
||||
nyashstd = { builtin = true }
|
||||
|
||||
# === ブラウザ・Web API ===
|
||||
browser_api = {
|
||||
bid = ["./apis/canvas.yaml", "./apis/dom.yaml", "./apis/webaudio.yaml"],
|
||||
target_environments = ["browser"]
|
||||
}
|
||||
webgl_api = {
|
||||
bid = "./apis/webgl.yaml",
|
||||
target_environments = ["browser"]
|
||||
}
|
||||
|
||||
# === システム・OS API ===
|
||||
system_api = {
|
||||
bid = ["./apis/libc.yaml", "./apis/filesystem.yaml", "./apis/network.yaml"],
|
||||
library = "system",
|
||||
target_environments = ["linux", "macos", "windows"]
|
||||
}
|
||||
posix_api = {
|
||||
bid = "./apis/posix.yaml",
|
||||
library = "system",
|
||||
target_environments = ["linux", "macos"]
|
||||
}
|
||||
|
||||
# === 機械学習・データサイエンス ===
|
||||
ml_api = {
|
||||
bid = ["./apis/opencv.yaml", "./apis/numpy.yaml"],
|
||||
library = ["./libs/opencv.so", "./libs/numpy.so"],
|
||||
target_environments = ["linux", "macos"]
|
||||
}
|
||||
tensorflow_api = {
|
||||
bid = "./apis/tensorflow.yaml",
|
||||
library = "./libs/tensorflow.so",
|
||||
optional = true # 環境によってオプション
|
||||
}
|
||||
|
||||
# === ゲーム開発 ===
|
||||
game_api = {
|
||||
bid = ["./apis/sdl.yaml", "./apis/opengl.yaml"],
|
||||
library = ["SDL2", "OpenGL"],
|
||||
target_environments = ["linux", "macos", "windows"]
|
||||
}
|
||||
|
||||
# === データベース ===
|
||||
database_api = {
|
||||
bid = ["./apis/sqlite.yaml", "./apis/postgresql.yaml"],
|
||||
library = ["sqlite3", "pq"],
|
||||
}
|
||||
|
||||
# === ネットワーク・Web ===
|
||||
http_api = {
|
||||
bid = "./apis/http_client.yaml",
|
||||
library = "curl"
|
||||
}
|
||||
|
||||
# === Nyashモジュール(従来通り) ===
|
||||
mylib = { path = "./src/mylib.hako" }
|
||||
utils = { path = "./src/utils/" }
|
||||
models = { path = "./src/models.hako" }
|
||||
|
||||
# === 将来の外部パッケージ ===
|
||||
awesome_lib = {
|
||||
version = "^1.2.0",
|
||||
registry = "nyash-pkg",
|
||||
bid = "auto" # パッケージレジストリから自動取得
|
||||
}
|
||||
|
||||
[build]
|
||||
entry_point = "./src/main.hako"
|
||||
backends = ["vm", "wasm", "aot"]
|
||||
optimization_level = "release"
|
||||
|
||||
[targets]
|
||||
browser = ["browser_api", "webgl_api"]
|
||||
desktop = ["system_api", "game_api", "ml_api"]
|
||||
server = ["system_api", "database_api", "http_api"]
|
||||
|
||||
[optimization]
|
||||
# MIRレベル最適化設定
|
||||
enable_effect_optimization = true
|
||||
enable_batch_optimization = true # FFI-ABI呼び出しバッチ化
|
||||
enable_gpu_acceleration = true
|
||||
cache_bid_compilation = true
|
||||
```
|
||||
|
||||
### 3. BIDエコシステム(標準API集)
|
||||
```
|
||||
nyash-std-apis/ # 標準APIライブラリ
|
||||
├── browser/
|
||||
│ ├── canvas.yaml # Canvas API
|
||||
│ ├── dom.yaml # DOM API
|
||||
│ ├── webaudio.yaml # Web Audio API
|
||||
│ ├── webgl.yaml # WebGL API
|
||||
│ └── fetch.yaml # Fetch API
|
||||
├── system/
|
||||
│ ├── libc.yaml # C標準ライブラリ
|
||||
│ ├── filesystem.yaml # ファイルシステム
|
||||
│ ├── network.yaml # ネットワーク
|
||||
│ ├── process.yaml # プロセス管理
|
||||
│ └── threads.yaml # スレッド・並行処理
|
||||
├── ml/
|
||||
│ ├── opencv.yaml # コンピューターヴィジョン
|
||||
│ ├── numpy.yaml # 数値計算
|
||||
│ ├── tensorflow.yaml # 機械学習
|
||||
│ └── pytorch.yaml # 深層学習
|
||||
├── game/
|
||||
│ ├── sdl.yaml # SDL2ライブラリ
|
||||
│ ├── opengl.yaml # OpenGL API
|
||||
│ ├── vulkan.yaml # Vulkan API
|
||||
│ └── physics.yaml # 物理エンジン
|
||||
├── database/
|
||||
│ ├── sqlite.yaml # SQLite
|
||||
│ ├── postgresql.yaml # PostgreSQL
|
||||
│ ├── mysql.yaml # MySQL
|
||||
│ └── redis.yaml # Redis
|
||||
└── crypto/
|
||||
├── openssl.yaml # OpenSSL
|
||||
├── libsodium.yaml # libsodium
|
||||
└── bcrypt.yaml # bcrypt
|
||||
```
|
||||
|
||||
## 🚀 段階的実装戦略(現実的ロードマップ)
|
||||
|
||||
### Phase 0: 基盤構築(2-3週間)
|
||||
```rust
|
||||
// 🎯 最小実装目標
|
||||
// using nyashstd → 動作
|
||||
```
|
||||
|
||||
#### **実装内容**
|
||||
1. **USINGトークナイザー** - `TokenType::USING`追加
|
||||
2. **基本パーサー** - `using nyashstd`構文解析
|
||||
3. **BuiltinStdlib基盤** - 組み込み標準ライブラリ
|
||||
4. **基本string関数** - upper, lower, split, join
|
||||
|
||||
#### **テスト**
|
||||
```nyash
|
||||
using nyashstd
|
||||
assert(string.upper("hello") == "HELLO")
|
||||
```
|
||||
|
||||
### Phase 1: BID基盤(4-6週間)
|
||||
```rust
|
||||
// 🎯 外部API基盤目標
|
||||
// using console_api → 動作(VM Stub)
|
||||
```
|
||||
|
||||
#### **実装内容**
|
||||
1. **BID読み込み** - YAML解析・検証システム
|
||||
2. **UniversalNamespaceRegistry** - 統合名前空間管理
|
||||
3. **MIR ExternCall統合** - BID→MIR変換
|
||||
4. **VM Stub実装** - console.log等の基本スタブ
|
||||
|
||||
#### **テスト**
|
||||
```nyash
|
||||
using nyashstd
|
||||
using console_api
|
||||
string.upper("test")
|
||||
console.log("BID integration works!")
|
||||
```
|
||||
|
||||
### Phase 2: WASM統合(6-8週間)
|
||||
```rust
|
||||
// 🎯 WASM動作目標
|
||||
// ブラウザでCanvas API動作
|
||||
```
|
||||
|
||||
#### **実装内容**
|
||||
1. **WASM RuntimeImports自動生成** - BID→WASM import
|
||||
2. **文字列マーシャリング** - UTF-8 (ptr,len)対応
|
||||
3. **Canvas API完全実装** - fillRect, fillText等
|
||||
4. **ブラウザテスト環境** - HTML/JS統合
|
||||
|
||||
#### **テスト**
|
||||
```nyash
|
||||
using browser_api
|
||||
canvas.fillRect("game-canvas", 10, 10, 100, 100, "red")
|
||||
```
|
||||
|
||||
### Phase 3: システムAPI統合(8-12週間)
|
||||
```rust
|
||||
// 🎯 ネイティブライブラリ動作目標
|
||||
// ファイルI/O, システムコール等
|
||||
```
|
||||
|
||||
#### **実装内容**
|
||||
1. **AOTバックエンド統合** - LLVM IR外部関数
|
||||
2. **システムライブラリ連携** - libc, filesystem等
|
||||
3. **エラーハンドリング統合** - 統一エラーモデル
|
||||
4. **パフォーマンス最適化** - バッチ処理・GPU加速
|
||||
|
||||
#### **テスト**
|
||||
```nyash
|
||||
using system_api
|
||||
local content = file.read("/etc/passwd")
|
||||
file.write("./output.txt", content)
|
||||
```
|
||||
|
||||
### Phase 4: 完全エコシステム(12-16週間)
|
||||
```rust
|
||||
// 🎯 実用的アプリケーション開発
|
||||
// ゲーム・ML・Webアプリ等
|
||||
```
|
||||
|
||||
#### **実装内容**
|
||||
1. **標準APIライブラリ** - nyash-std-apis完成
|
||||
2. **パッケージレジストリ** - BID共有システム
|
||||
3. **IDE Language Server** - 統合補完・エラー検出
|
||||
4. **最適化エンジン** - Effect System活用
|
||||
|
||||
#### **実用例**
|
||||
```nyash
|
||||
# 本格的なゲーム開発
|
||||
using game_api
|
||||
using audio_api
|
||||
game.sdl.createWindow("My Game", 1024, 768)
|
||||
audio.mixer.playMusic("bgm.ogg")
|
||||
```
|
||||
|
||||
## 📊 既存実装との整合性
|
||||
|
||||
### Phase 9.75eとの関係
|
||||
```
|
||||
Phase 9.75e (既存計画) なんでもAPI計画 (新設計)
|
||||
↓ ↓
|
||||
namespace構文 using統一構文
|
||||
依存関係システム → nyash.link統合管理
|
||||
外部ファイル読み込み → BID統合システム
|
||||
↓
|
||||
完全統合アーキテクチャ
|
||||
```
|
||||
|
||||
### 既存MIR/バックエンドとの統合
|
||||
- ✅ **MIR ExternCall**: 既存実装活用
|
||||
- ✅ **WASM RuntimeImports**: 既存基盤拡張
|
||||
- ✅ **VM Backend**: 既存スタブシステム活用
|
||||
- 🔧 **統合課題**: usingシステムとの橋渡し
|
||||
|
||||
## 🌟 長期ビジョン:Nyashの未来
|
||||
|
||||
### 2025年目標
|
||||
- **Phase 0-1完了**: 基盤・BID統合
|
||||
- **実用アプリ**: シンプルなブラウザゲーム・ツール
|
||||
- **コミュニティ**: 開発者コミュニティ形成
|
||||
|
||||
### 2026年目標
|
||||
- **Phase 2-3完了**: WASM・システムAPI統合
|
||||
- **本格アプリ**: ゲーム・データサイエンス・Webアプリ
|
||||
- **エコシステム**: BIDライブラリエコシステム
|
||||
|
||||
### 2027年目標
|
||||
- **Phase 4完了**: 完全エコシステム
|
||||
- **産業利用**: 企業での実用的活用
|
||||
- **言語標準化**: BID標準の業界採用
|
||||
|
||||
## 🎯 即座に開始すべき実装
|
||||
|
||||
### 今日のアクション
|
||||
1. **src/stdlib/mod.rs作成** - 組み込み標準ライブラリ基盤
|
||||
2. **TokenType::USING追加** - トークナイザー拡張
|
||||
3. **Phase 0実装開始** - using nyashstd基本動作
|
||||
|
||||
### 今週のアクション
|
||||
4. **BuiltinStdlib::new()実装** - string関数4種
|
||||
5. **基本テスト作成** - using動作確認
|
||||
6. **Phase 1設計** - BID統合詳細設計
|
||||
|
||||
### 来週のアクション
|
||||
7. **BID読み込み基盤** - YAML解析システム
|
||||
8. **UniversalNamespaceRegistry** - 統合名前空間管理
|
||||
9. **console.log実装** - 最初のBID統合テスト
|
||||
|
||||
---
|
||||
|
||||
**🎉 この最終統合アーキテクチャにより、Nyashが真に「なんでもできる」革命的プログラミング言語になるにゃ!**
|
||||
|
||||
**🚀 今すぐPhase 0実装を開始して、プログラミング言語の未来を創造しよう!🐱✨**
|
||||
@ -1,435 +0,0 @@
|
||||
# 最小実装:標準関数優先namespace/usingシステム
|
||||
|
||||
## 🎯 基本戦略:nyash.link前の段階的実装
|
||||
|
||||
### 📊 現状分析
|
||||
- **既存Box型**: 25種類以上の豊富なBox実装
|
||||
- **include使用**: 限定的(text_adventure例のみ)
|
||||
- **using実装**: 完全未実装→新規作成可能
|
||||
- **最優先課題**: 複雑なファイル依存関係システムより、まず標準関数のIDE補完
|
||||
|
||||
### 🌟 段階的実装アプローチ
|
||||
|
||||
#### **Phase 0: 組み込みnyashstd(最小実装)**
|
||||
```
|
||||
ファイル読み込み一切なし → インタープリターに直接組み込み
|
||||
```
|
||||
|
||||
#### **Phase 1: using構文**
|
||||
```nyash
|
||||
using nyashstd
|
||||
string.upper("hello") # ✅ 動作
|
||||
```
|
||||
|
||||
#### **Phase 2: 将来のnyash.link対応**
|
||||
```
|
||||
外部ファイル・依存関係システム(後日実装)
|
||||
```
|
||||
|
||||
## 🏗️ 組み込みnyashstd設計
|
||||
|
||||
### 優先順位別Box分類
|
||||
|
||||
#### 🚨 **Tier 1: 最優先基本機能**
|
||||
```rust
|
||||
// 使用頻度最高・IDE補完必須
|
||||
- string_box.rs → nyashstd.string.*
|
||||
- math_box.rs → nyashstd.math.*
|
||||
- array/mod.rs → nyashstd.array.*
|
||||
- console_box.rs → nyashstd.io.*
|
||||
```
|
||||
|
||||
#### ⚡ **Tier 2: 重要機能**
|
||||
```rust
|
||||
// 標準的な機能
|
||||
- time_box.rs → nyashstd.time.*
|
||||
- random_box.rs → nyashstd.random.*
|
||||
- map_box.rs → nyashstd.map.*
|
||||
```
|
||||
|
||||
#### 📝 **Tier 3: 特殊用途**
|
||||
```rust
|
||||
// 特定用途・後で追加
|
||||
- debug_box.rs → nyashstd.debug.*
|
||||
- http_server_box.rs → nyashstd.http.*
|
||||
- p2p_box.rs → nyashstd.p2p.*
|
||||
```
|
||||
|
||||
### 最小実装スコープ(Phase 0)
|
||||
|
||||
#### **nyashstd.string機能**
|
||||
```nyash
|
||||
using nyashstd
|
||||
|
||||
string.upper("hello") # "HELLO"
|
||||
string.lower("WORLD") # "world"
|
||||
string.split("a,b,c", ",") # ["a", "b", "c"]
|
||||
string.join(["a","b"], "-") # "a-b"
|
||||
string.length("test") # 4
|
||||
```
|
||||
|
||||
#### **nyashstd.math機能**
|
||||
```nyash
|
||||
using nyashstd
|
||||
|
||||
math.sin(3.14159) # 0.0 (approximately)
|
||||
math.cos(0) # 1.0
|
||||
math.sqrt(16) # 4.0
|
||||
math.floor(3.7) # 3
|
||||
math.random() # 0.0-1.0のランダム値
|
||||
```
|
||||
|
||||
#### **nyashstd.array機能**
|
||||
```nyash
|
||||
using nyashstd
|
||||
|
||||
array.length([1,2,3]) # 3
|
||||
array.push([1,2], 3) # [1,2,3]
|
||||
array.get([1,2,3], 1) # 2
|
||||
array.slice([1,2,3,4], 1, 3) # [2,3]
|
||||
```
|
||||
|
||||
#### **nyashstd.io機能**
|
||||
```nyash
|
||||
using nyashstd
|
||||
|
||||
io.print("Hello") # コンソール出力
|
||||
io.println("World") # 改行付き出力
|
||||
io.debug("Debug info") # デバッグ出力
|
||||
```
|
||||
|
||||
## 💻 技術実装戦略
|
||||
|
||||
### 1. インタープリター組み込み方式
|
||||
|
||||
#### **新ファイル: `src/stdlib/mod.rs`**
|
||||
```rust
|
||||
//! 組み込み標準ライブラリ
|
||||
//! nyash.linkなしで動作する基本的な標準関数群
|
||||
|
||||
use crate::boxes::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct BuiltinStdlib {
|
||||
pub namespaces: HashMap<String, BuiltinNamespace>,
|
||||
}
|
||||
|
||||
pub struct BuiltinNamespace {
|
||||
pub name: String,
|
||||
pub static_boxes: HashMap<String, BuiltinStaticBox>,
|
||||
}
|
||||
|
||||
pub struct BuiltinStaticBox {
|
||||
pub name: String,
|
||||
pub methods: HashMap<String, BuiltinMethod>,
|
||||
}
|
||||
|
||||
pub type BuiltinMethod = fn(&[Box<dyn NyashBox>]) -> Result<Box<dyn NyashBox>, RuntimeError>;
|
||||
|
||||
impl BuiltinStdlib {
|
||||
pub fn new() -> Self {
|
||||
let mut stdlib = BuiltinStdlib {
|
||||
namespaces: HashMap::new(),
|
||||
};
|
||||
|
||||
// nyashstd名前空間登録
|
||||
stdlib.register_nyashstd();
|
||||
|
||||
stdlib
|
||||
}
|
||||
|
||||
fn register_nyashstd(&mut self) {
|
||||
let mut nyashstd = BuiltinNamespace {
|
||||
name: "nyashstd".to_string(),
|
||||
static_boxes: HashMap::new(),
|
||||
};
|
||||
|
||||
// string static box
|
||||
nyashstd.static_boxes.insert("string".to_string(), self.create_string_box());
|
||||
// math static box
|
||||
nyashstd.static_boxes.insert("math".to_string(), self.create_math_box());
|
||||
// array static box
|
||||
nyashstd.static_boxes.insert("array".to_string(), self.create_array_box());
|
||||
// io static box
|
||||
nyashstd.static_boxes.insert("io".to_string(), self.create_io_box());
|
||||
|
||||
self.namespaces.insert("nyashstd".to_string(), nyashstd);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **文字列関数実装例**
|
||||
```rust
|
||||
impl BuiltinStdlib {
|
||||
fn create_string_box(&self) -> BuiltinStaticBox {
|
||||
let mut string_box = BuiltinStaticBox {
|
||||
name: "string".to_string(),
|
||||
methods: HashMap::new(),
|
||||
};
|
||||
|
||||
// string.upper(str) -> String
|
||||
string_box.methods.insert("upper".to_string(), |args| {
|
||||
if args.len() != 1 {
|
||||
return Err(RuntimeError::InvalidArguments(
|
||||
"string.upper() takes exactly 1 argument".to_string()
|
||||
));
|
||||
}
|
||||
|
||||
let string_arg = args[0].to_string_box();
|
||||
let result = StringBox::new(&string_arg.value.to_uppercase());
|
||||
Ok(Box::new(result))
|
||||
});
|
||||
|
||||
// string.lower(str) -> String
|
||||
string_box.methods.insert("lower".to_string(), |args| {
|
||||
if args.len() != 1 {
|
||||
return Err(RuntimeError::InvalidArguments(
|
||||
"string.lower() takes exactly 1 argument".to_string()
|
||||
));
|
||||
}
|
||||
|
||||
let string_arg = args[0].to_string_box();
|
||||
let result = StringBox::new(&string_arg.value.to_lowercase());
|
||||
Ok(Box::new(result))
|
||||
});
|
||||
|
||||
// string.split(str, separator) -> Array
|
||||
string_box.methods.insert("split".to_string(), |args| {
|
||||
if args.len() != 2 {
|
||||
return Err(RuntimeError::InvalidArguments(
|
||||
"string.split() takes exactly 2 arguments".to_string()
|
||||
));
|
||||
}
|
||||
|
||||
let string_arg = args[0].to_string_box();
|
||||
let sep_arg = args[1].to_string_box();
|
||||
|
||||
let string_box = StringBox::new(&string_arg.value);
|
||||
let result = string_box.split(&sep_arg.value)?;
|
||||
Ok(result)
|
||||
});
|
||||
|
||||
string_box
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. インタープリター統合
|
||||
|
||||
#### **インタープリター拡張: `src/interpreter/core.rs`**
|
||||
```rust
|
||||
use crate::stdlib::BuiltinStdlib;
|
||||
|
||||
pub struct NyashInterpreter {
|
||||
// 既存フィールド...
|
||||
pub builtin_stdlib: BuiltinStdlib,
|
||||
pub using_imports: HashMap<String, Vec<String>>, // ファイル別インポート
|
||||
}
|
||||
|
||||
impl NyashInterpreter {
|
||||
pub fn new() -> Self {
|
||||
NyashInterpreter {
|
||||
// 既存初期化...
|
||||
builtin_stdlib: BuiltinStdlib::new(),
|
||||
using_imports: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
// using文実行
|
||||
pub fn execute_using(&mut self, namespace_name: &str) -> Result<(), RuntimeError> {
|
||||
// 組み込み名前空間かチェック
|
||||
if self.builtin_stdlib.namespaces.contains_key(namespace_name) {
|
||||
// 現在ファイルのインポートリストに追加
|
||||
self.using_imports
|
||||
.entry(self.current_file_id.clone())
|
||||
.or_insert_with(Vec::new)
|
||||
.push(namespace_name.to_string());
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(RuntimeError::UndefinedNamespace(namespace_name.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
// 短縮名解決: string.upper() -> nyashstd.string.upper()
|
||||
pub fn resolve_short_call(&self, box_name: &str, method_name: &str)
|
||||
-> Option<(&str, &str, &str)> { // (namespace, box, method)
|
||||
|
||||
if let Some(imports) = self.using_imports.get(&self.current_file_id) {
|
||||
for namespace_name in imports {
|
||||
if let Some(namespace) = self.builtin_stdlib.namespaces.get(namespace_name) {
|
||||
if namespace.static_boxes.contains_key(box_name) {
|
||||
return Some((namespace_name, box_name, method_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
// 組み込み関数呼び出し
|
||||
pub fn call_builtin_method(&self, namespace: &str, box_name: &str, method_name: &str, args: Vec<Box<dyn NyashBox>>)
|
||||
-> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
|
||||
if let Some(ns) = self.builtin_stdlib.namespaces.get(namespace) {
|
||||
if let Some(static_box) = ns.static_boxes.get(box_name) {
|
||||
if let Some(method) = static_box.methods.get(method_name) {
|
||||
return method(&args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(RuntimeError::UndefinedMethod(
|
||||
format!("{}.{}.{}", namespace, box_name, method_name)
|
||||
))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. パーサー最小拡張
|
||||
|
||||
#### **トークナイザー: `src/tokenizer.rs`**
|
||||
```rust
|
||||
pub enum TokenType {
|
||||
// 既存...
|
||||
USING, // using キーワード
|
||||
// NAMESPACE は後のPhaseで追加
|
||||
}
|
||||
```
|
||||
|
||||
#### **AST最小拡張: `src/ast.rs`**
|
||||
```rust
|
||||
pub enum ASTNode {
|
||||
// 既存...
|
||||
UsingStatement {
|
||||
namespace_name: String, // "nyashstd" のみ対応
|
||||
span: Span,
|
||||
},
|
||||
// QualifiedCall は後のPhaseで追加
|
||||
}
|
||||
```
|
||||
|
||||
#### **パーサー: `src/parser/statements.rs`**
|
||||
```rust
|
||||
impl NyashParser {
|
||||
pub fn parse_using(&mut self) -> Result<ASTNode, ParseError> {
|
||||
self.advance(); // consume 'using'
|
||||
|
||||
if let TokenType::IDENTIFIER(namespace_name) = &self.current_token().token_type {
|
||||
let name = namespace_name.clone();
|
||||
self.advance();
|
||||
|
||||
// Phase 0では "nyashstd" のみ許可
|
||||
if name != "nyashstd" {
|
||||
return Err(ParseError::UnsupportedNamespace(name));
|
||||
}
|
||||
|
||||
Ok(ASTNode::UsingStatement {
|
||||
namespace_name: name,
|
||||
span: self.current_span(),
|
||||
})
|
||||
} else {
|
||||
Err(ParseError::ExpectedIdentifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🧪 テスト戦略
|
||||
|
||||
### Phase 0テストケース
|
||||
|
||||
#### **基本using文テスト**
|
||||
```nyash
|
||||
# test_using_basic.hako
|
||||
using nyashstd
|
||||
|
||||
local result = string.upper("hello")
|
||||
assert(result == "HELLO")
|
||||
|
||||
local lower = string.lower("WORLD")
|
||||
assert(lower == "world")
|
||||
```
|
||||
|
||||
#### **数学関数テスト**
|
||||
```nyash
|
||||
# test_math_basic.hako
|
||||
using nyashstd
|
||||
|
||||
local sin_result = math.sin(0)
|
||||
assert(sin_result == 0)
|
||||
|
||||
local sqrt_result = math.sqrt(16)
|
||||
assert(sqrt_result == 4)
|
||||
```
|
||||
|
||||
#### **配列操作テスト**
|
||||
```nyash
|
||||
# test_array_basic.hako
|
||||
using nyashstd
|
||||
|
||||
local arr = [1, 2, 3]
|
||||
local length = array.length(arr)
|
||||
assert(length == 3)
|
||||
|
||||
local item = array.get(arr, 1)
|
||||
assert(item == 2)
|
||||
```
|
||||
|
||||
## 📊 実装マイルストーン
|
||||
|
||||
### ✅ Phase 0完了条件
|
||||
- [ ] USING トークン認識
|
||||
- [ ] using nyashstd 構文解析
|
||||
- [ ] 組み込みnyashstd.string実装
|
||||
- [ ] 組み込みnyashstd.math実装
|
||||
- [ ] 組み込みnyashstd.array実装
|
||||
- [ ] 組み込みnyashstd.io実装
|
||||
- [ ] 基本テストケース全通過
|
||||
|
||||
### 🔮 将来の発展
|
||||
|
||||
#### **Phase 1: 完全修飾名対応**
|
||||
```nyash
|
||||
# using不要でも使える
|
||||
nyashstd.string.upper("hello")
|
||||
```
|
||||
|
||||
#### **Phase 2: namespace構文対応**
|
||||
```nyash
|
||||
# 組み込み以外の名前空間
|
||||
namespace mylib {
|
||||
static box utils {
|
||||
static process(data) { ... }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **Phase 3: nyash.link統合**
|
||||
```toml
|
||||
# nyash.link
|
||||
[dependencies]
|
||||
mylib = { path = "./mylib.hako" }
|
||||
```
|
||||
|
||||
## 🎯 実装優先順位
|
||||
|
||||
### 🚨 Critical(今すぐ)
|
||||
1. **USINGトークナイザー** - Token::USING追加
|
||||
2. **using文パーサー** - "using nyashstd"解析
|
||||
3. **BuiltinStdlib基盤** - src/stdlib/mod.rs作成
|
||||
|
||||
### ⚡ High(今週中)
|
||||
4. **string関数実装** - upper, lower, split, join
|
||||
5. **math関数実装** - sin, cos, sqrt, floor
|
||||
6. **基本テスト** - using nyashstd動作確認
|
||||
|
||||
### 📝 Medium(来週)
|
||||
7. **array関数実装** - length, get, push, slice
|
||||
8. **io関数実装** - print, println, debug
|
||||
9. **エラーハンドリング** - 適切なエラーメッセージ
|
||||
|
||||
---
|
||||
|
||||
**🎉 この戦略なら複雑なファイル依存関係システムなしで、すぐに実用的なnamespace/usingが実現できるにゃ!🐱**
|
||||
@ -1,625 +0,0 @@
|
||||
# なんでもAPI計画:実世界での具体例
|
||||
|
||||
## 🌟 革命的開発体験の実例
|
||||
|
||||
### 🎮 ゲーム開発例:Nyashブラウザゲーム
|
||||
```nyash
|
||||
# === nyash.link ===
|
||||
[dependencies]
|
||||
nyashstd = { builtin = true }
|
||||
canvas_api = { bid = "./apis/canvas.yaml" }
|
||||
dom_api = { bid = "./apis/dom.yaml" }
|
||||
audio_api = { bid = "./apis/webaudio.yaml" }
|
||||
|
||||
# === game.hako ===
|
||||
using nyashstd
|
||||
using canvas_api
|
||||
using dom_api
|
||||
using audio_api
|
||||
|
||||
static box Game {
|
||||
init { canvas_id, score, player_x, player_y, enemies }
|
||||
|
||||
main() {
|
||||
me.canvas_id = "game-canvas"
|
||||
me.score = 0
|
||||
me.player_x = 200
|
||||
me.player_y = 300
|
||||
me.enemies = new ArrayBox()
|
||||
|
||||
# DOMイベント設定(FFI-ABI経由)
|
||||
dom.addEventListener("keydown", me.handleKeyDown)
|
||||
|
||||
# ゲームループ開始
|
||||
me.gameLoop()
|
||||
}
|
||||
|
||||
gameLoop() {
|
||||
loop(true) {
|
||||
me.update()
|
||||
me.render()
|
||||
|
||||
# ブラウザのrequestAnimationFrame(FFI-ABI)
|
||||
dom.requestAnimationFrame(me.gameLoop)
|
||||
}
|
||||
}
|
||||
|
||||
update() {
|
||||
# 敵の移動(組み込み標準ライブラリ)
|
||||
local i = 0
|
||||
loop(i < array.length(me.enemies)) {
|
||||
local enemy = array.get(me.enemies, i)
|
||||
enemy.y = enemy.y + enemy.speed
|
||||
i = i + 1
|
||||
}
|
||||
|
||||
# 当たり判定(組み込み数学関数)
|
||||
local distance = math.sqrt(
|
||||
math.pow(me.player_x - enemy.x, 2) +
|
||||
math.pow(me.player_y - enemy.y, 2)
|
||||
)
|
||||
|
||||
if distance < 30 {
|
||||
me.gameOver()
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
# 画面クリア(Canvas API - FFI-ABI)
|
||||
canvas.fillRect(me.canvas_id, 0, 0, 800, 600, "black")
|
||||
|
||||
# プレイヤー描画
|
||||
canvas.fillRect(me.canvas_id, me.player_x, me.player_y, 20, 20, "blue")
|
||||
|
||||
# 敵描画
|
||||
local i = 0
|
||||
loop(i < array.length(me.enemies)) {
|
||||
local enemy = array.get(me.enemies, i)
|
||||
canvas.fillRect(me.canvas_id, enemy.x, enemy.y, 15, 15, "red")
|
||||
i = i + 1
|
||||
}
|
||||
|
||||
# スコア表示
|
||||
local score_text = "Score: " + string.toString(me.score)
|
||||
canvas.fillText(me.canvas_id, score_text, 10, 30, "20px Arial", "white")
|
||||
}
|
||||
|
||||
handleKeyDown(event) {
|
||||
# キーボード入力処理(DOM API経由)
|
||||
local key = dom.getEventKey(event)
|
||||
|
||||
if key == "ArrowLeft" {
|
||||
me.player_x = me.player_x - 10
|
||||
} else if key == "ArrowRight" {
|
||||
me.player_x = me.player_x + 10
|
||||
} else if key == " " { # スペースキー
|
||||
me.shoot()
|
||||
}
|
||||
}
|
||||
|
||||
shoot() {
|
||||
# 効果音再生(Web Audio API - FFI-ABI)
|
||||
audio.playSound("shoot.wav")
|
||||
|
||||
# 弾の生成・発射処理
|
||||
# ...
|
||||
}
|
||||
|
||||
gameOver() {
|
||||
# ゲームオーバー処理
|
||||
audio.playSound("gameover.wav")
|
||||
dom.alert("Game Over! Score: " + string.toString(me.score))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 🔬 データサイエンス例:画像処理アプリ
|
||||
```nyash
|
||||
# === nyash.link ===
|
||||
[dependencies]
|
||||
nyashstd = { builtin = true }
|
||||
opencv_api = { bid = "./apis/opencv.yaml", library = "./libs/opencv.so" }
|
||||
numpy_api = { bid = "./apis/numpy.yaml", library = "./libs/numpy.so" }
|
||||
matplotlib_api = { bid = "./apis/matplotlib.yaml", library = "./libs/matplotlib.so" }
|
||||
file_api = { bid = "./apis/file.yaml" }
|
||||
|
||||
# === image_processor.hako ===
|
||||
using nyashstd
|
||||
using opencv_api
|
||||
using numpy_api
|
||||
using matplotlib_api
|
||||
using file_api
|
||||
|
||||
static box ImageProcessor {
|
||||
init { input_path, output_path, processed_data }
|
||||
|
||||
main() {
|
||||
me.input_path = "./images/input.jpg"
|
||||
me.output_path = "./images/output.jpg"
|
||||
|
||||
# 画像読み込み(OpenCV - FFI-ABI)
|
||||
local image = opencv.imread(me.input_path)
|
||||
|
||||
# 前処理
|
||||
local gray = opencv.cvtColor(image, "BGR2GRAY")
|
||||
local blurred = opencv.gaussianBlur(gray, 5, 5)
|
||||
|
||||
# エッジ検出
|
||||
local edges = opencv.canny(blurred, 50, 150)
|
||||
|
||||
# NumPy配列操作(NumPy - FFI-ABI)
|
||||
local edge_array = numpy.fromOpenCV(edges)
|
||||
local normalized = numpy.normalize(edge_array, 0, 255)
|
||||
|
||||
# 統計計算(組み込み標準ライブラリ)
|
||||
local edge_count = me.countEdgePixels(normalized)
|
||||
local percentage = (edge_count * 100) / (image.width * image.height)
|
||||
|
||||
# 結果表示
|
||||
io.println("Edge pixels: " + string.toString(edge_count))
|
||||
io.println("Edge percentage: " + string.toString(percentage) + "%")
|
||||
|
||||
# 結果画像保存(OpenCV)
|
||||
opencv.imwrite(me.output_path, edges)
|
||||
|
||||
# グラフ生成(Matplotlib - FFI-ABI)
|
||||
me.generateHistogram(normalized)
|
||||
}
|
||||
|
||||
countEdgePixels(image_array) {
|
||||
local count = 0
|
||||
local height = numpy.shape(image_array, 0)
|
||||
local width = numpy.shape(image_array, 1)
|
||||
|
||||
local y = 0
|
||||
loop(y < height) {
|
||||
local x = 0
|
||||
loop(x < width) {
|
||||
local pixel = numpy.get(image_array, y, x)
|
||||
if pixel > 0 {
|
||||
count = count + 1
|
||||
}
|
||||
x = x + 1
|
||||
}
|
||||
y = y + 1
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
generateHistogram(image_array) {
|
||||
# ヒストグラム計算(NumPy)
|
||||
local histogram = numpy.histogram(image_array, 256)
|
||||
|
||||
# グラフ描画(Matplotlib)
|
||||
matplotlib.figure(800, 600)
|
||||
matplotlib.plot(histogram.bins, histogram.values)
|
||||
matplotlib.title("Edge Pixel Histogram")
|
||||
matplotlib.xlabel("Pixel Intensity")
|
||||
matplotlib.ylabel("Frequency")
|
||||
matplotlib.savefig("./images/histogram.png")
|
||||
matplotlib.show()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 🌐 Webサーバー例:RESTful API
|
||||
```nyash
|
||||
# === nyash.link ===
|
||||
[dependencies]
|
||||
nyashstd = { builtin = true }
|
||||
http_server_api = { bid = "./apis/http_server.yaml" }
|
||||
sqlite_api = { bid = "./apis/sqlite.yaml", library = "./libs/sqlite.so" }
|
||||
json_api = { bid = "./apis/json.yaml" }
|
||||
crypto_api = { bid = "./apis/crypto.yaml", library = "./libs/openssl.so" }
|
||||
|
||||
# === api_server.hako ===
|
||||
using nyashstd
|
||||
using http_server_api
|
||||
using sqlite_api
|
||||
using json_api
|
||||
using crypto_api
|
||||
|
||||
static box ApiServer {
|
||||
init { server, database, port }
|
||||
|
||||
main() {
|
||||
me.port = 8080
|
||||
me.server = http_server.create()
|
||||
me.database = sqlite.open("./data/app.db")
|
||||
|
||||
# データベース初期化
|
||||
me.initDatabase()
|
||||
|
||||
# ルート設定
|
||||
http_server.route(me.server, "GET", "/api/users", me.getUsers)
|
||||
http_server.route(me.server, "POST", "/api/users", me.createUser)
|
||||
http_server.route(me.server, "PUT", "/api/users/:id", me.updateUser)
|
||||
http_server.route(me.server, "DELETE", "/api/users/:id", me.deleteUser)
|
||||
|
||||
# サーバー開始
|
||||
io.println("Server starting on port " + string.toString(me.port))
|
||||
http_server.listen(me.server, me.port)
|
||||
}
|
||||
|
||||
initDatabase() {
|
||||
local sql = "CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
email TEXT UNIQUE NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)"
|
||||
|
||||
sqlite.exec(me.database, sql)
|
||||
}
|
||||
|
||||
getUsers(request, response) {
|
||||
# クエリ実行(SQLite - FFI-ABI)
|
||||
local sql = "SELECT id, name, email, created_at FROM users"
|
||||
local results = sqlite.query(me.database, sql)
|
||||
|
||||
# JSON変換(JSON API - FFI-ABI)
|
||||
local json_response = json.stringify(results)
|
||||
|
||||
# レスポンス送信(HTTP Server API)
|
||||
http_server.setHeader(response, "Content-Type", "application/json")
|
||||
http_server.setStatus(response, 200)
|
||||
http_server.send(response, json_response)
|
||||
}
|
||||
|
||||
createUser(request, response) {
|
||||
# リクエストボディ解析
|
||||
local body = http_server.getBody(request)
|
||||
local user_data = json.parse(body)
|
||||
|
||||
# バリデーション(組み込み標準ライブラリ)
|
||||
if string.length(user_data.name) < 2 {
|
||||
me.sendError(response, 400, "Name must be at least 2 characters")
|
||||
return
|
||||
}
|
||||
|
||||
if not me.isValidEmail(user_data.email) {
|
||||
me.sendError(response, 400, "Invalid email format")
|
||||
return
|
||||
}
|
||||
|
||||
# パスワードハッシュ化(Crypto API - FFI-ABI)
|
||||
local password_hash = crypto.hashPassword(user_data.password)
|
||||
|
||||
# データベース挿入
|
||||
local sql = "INSERT INTO users (name, email, password_hash) VALUES (?, ?, ?)"
|
||||
local params = [user_data.name, user_data.email, password_hash]
|
||||
|
||||
try {
|
||||
local user_id = sqlite.insert(me.database, sql, params)
|
||||
|
||||
# 作成されたユーザー情報を返す
|
||||
local created_user = map.create()
|
||||
map.set(created_user, "id", user_id)
|
||||
map.set(created_user, "name", user_data.name)
|
||||
map.set(created_user, "email", user_data.email)
|
||||
|
||||
local json_response = json.stringify(created_user)
|
||||
|
||||
http_server.setHeader(response, "Content-Type", "application/json")
|
||||
http_server.setStatus(response, 201)
|
||||
http_server.send(response, json_response)
|
||||
|
||||
} catch error {
|
||||
io.println("Database error: " + error.message)
|
||||
me.sendError(response, 500, "Failed to create user")
|
||||
}
|
||||
}
|
||||
|
||||
isValidEmail(email) {
|
||||
# 簡単なメール検証(組み込み文字列関数)
|
||||
local at_pos = string.indexOf(email, "@")
|
||||
local dot_pos = string.lastIndexOf(email, ".")
|
||||
|
||||
return at_pos > 0 and dot_pos > at_pos and dot_pos < string.length(email) - 1
|
||||
}
|
||||
|
||||
sendError(response, status, message) {
|
||||
local error_obj = map.create()
|
||||
map.set(error_obj, "error", message)
|
||||
|
||||
local json_error = json.stringify(error_obj)
|
||||
|
||||
http_server.setHeader(response, "Content-Type", "application/json")
|
||||
http_server.setStatus(response, status)
|
||||
http_server.send(response, json_error)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 🔧 システムプログラミング例:ファイル監視ツール
|
||||
```nyash
|
||||
# === nyash.link ===
|
||||
[dependencies]
|
||||
nyashstd = { builtin = true }
|
||||
libc_api = { bid = "./apis/libc.yaml", library = "system" }
|
||||
inotify_api = { bid = "./apis/inotify.yaml", library = "system" }
|
||||
filesystem_api = { bid = "./apis/filesystem.yaml" }
|
||||
|
||||
# === file_monitor.hako ===
|
||||
using nyashstd
|
||||
using libc_api
|
||||
using inotify_api
|
||||
using filesystem_api
|
||||
|
||||
static box FileMonitor {
|
||||
init { watch_path, inotify_fd, watch_descriptors, callbacks }
|
||||
|
||||
main() {
|
||||
me.watch_path = "./watched_directory"
|
||||
me.watch_descriptors = new ArrayBox()
|
||||
me.callbacks = map.create()
|
||||
|
||||
# inotify初期化(Linux inotify - FFI-ABI)
|
||||
me.inotify_fd = inotify.init()
|
||||
|
||||
if me.inotify_fd < 0 {
|
||||
io.println("Failed to initialize inotify")
|
||||
return
|
||||
}
|
||||
|
||||
# ディレクトリ監視設定
|
||||
me.addWatch(me.watch_path)
|
||||
|
||||
# コールバック設定
|
||||
me.setupCallbacks()
|
||||
|
||||
io.println("File monitor started. Watching: " + me.watch_path)
|
||||
|
||||
# メインループ
|
||||
me.eventLoop()
|
||||
}
|
||||
|
||||
addWatch(path) {
|
||||
# 監視フラグ(inotify constants)
|
||||
local flags = inotify.IN_CREATE or inotify.IN_DELETE or
|
||||
inotify.IN_MODIFY or inotify.IN_MOVED_FROM or
|
||||
inotify.IN_MOVED_TO
|
||||
|
||||
local wd = inotify.addWatch(me.inotify_fd, path, flags)
|
||||
|
||||
if wd >= 0 {
|
||||
array.push(me.watch_descriptors, wd)
|
||||
io.println("Added watch for: " + path)
|
||||
} else {
|
||||
io.println("Failed to add watch for: " + path)
|
||||
}
|
||||
}
|
||||
|
||||
setupCallbacks() {
|
||||
# ファイル作成コールバック
|
||||
map.set(me.callbacks, "CREATE", static function(event) {
|
||||
io.println("File created: " + event.name)
|
||||
|
||||
# ファイル情報取得(Filesystem API)
|
||||
local file_info = filesystem.stat(event.path)
|
||||
local size = file_info.size
|
||||
local permissions = file_info.permissions
|
||||
|
||||
io.println(" Size: " + string.toString(size) + " bytes")
|
||||
io.println(" Permissions: " + permissions)
|
||||
})
|
||||
|
||||
# ファイル変更コールバック
|
||||
map.set(me.callbacks, "MODIFY", static function(event) {
|
||||
io.println("File modified: " + event.name)
|
||||
|
||||
# 変更時刻記録
|
||||
local timestamp = time.now()
|
||||
local formatted_time = time.format(timestamp, "%Y-%m-%d %H:%M:%S")
|
||||
io.println(" Modified at: " + formatted_time)
|
||||
})
|
||||
|
||||
# ファイル削除コールバック
|
||||
map.set(me.callbacks, "DELETE", static function(event) {
|
||||
io.println("File deleted: " + event.name)
|
||||
|
||||
# ログファイルに記録
|
||||
me.logEvent("DELETE", event.name, time.now())
|
||||
})
|
||||
}
|
||||
|
||||
eventLoop() {
|
||||
local buffer_size = 4096
|
||||
local buffer = libc.malloc(buffer_size)
|
||||
|
||||
loop(true) {
|
||||
# inotify eventsを読み取り(blocking read)
|
||||
local bytes_read = libc.read(me.inotify_fd, buffer, buffer_size)
|
||||
|
||||
if bytes_read > 0 {
|
||||
me.processEvents(buffer, bytes_read)
|
||||
} else if bytes_read == 0 {
|
||||
# EOF
|
||||
break
|
||||
} else {
|
||||
# エラー
|
||||
local error_code = libc.errno()
|
||||
io.println("Read error: " + string.toString(error_code))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
libc.free(buffer)
|
||||
}
|
||||
|
||||
processEvents(buffer, bytes_read) {
|
||||
local offset = 0
|
||||
|
||||
loop(offset < bytes_read) {
|
||||
# inotify_event構造体解析(libc memory operations)
|
||||
local event = inotify.parseEvent(buffer, offset)
|
||||
|
||||
# イベントタイプ判定
|
||||
local event_type = me.getEventType(event.mask)
|
||||
|
||||
# 対応するコールバック実行
|
||||
if map.has(me.callbacks, event_type) {
|
||||
local callback = map.get(me.callbacks, event_type)
|
||||
callback(event)
|
||||
}
|
||||
|
||||
# 次のイベントへ
|
||||
offset = offset + event.size
|
||||
}
|
||||
}
|
||||
|
||||
getEventType(mask) {
|
||||
if mask and inotify.IN_CREATE {
|
||||
return "CREATE"
|
||||
} else if mask and inotify.IN_MODIFY {
|
||||
return "MODIFY"
|
||||
} else if mask and inotify.IN_DELETE {
|
||||
return "DELETE"
|
||||
} else if mask and inotify.IN_MOVED_FROM {
|
||||
return "MOVE_FROM"
|
||||
} else if mask and inotify.IN_MOVED_TO {
|
||||
return "MOVE_TO"
|
||||
} else {
|
||||
return "UNKNOWN"
|
||||
}
|
||||
}
|
||||
|
||||
logEvent(event_type, filename, timestamp) {
|
||||
local log_entry = time.format(timestamp, "%Y-%m-%d %H:%M:%S") +
|
||||
" [" + event_type + "] " + filename + "\n"
|
||||
|
||||
# ログファイルに追記(Filesystem API)
|
||||
filesystem.appendFile("./file_monitor.log", log_entry)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 MIR同時拡張による最適化効果
|
||||
|
||||
### 🚀 最適化前後の比較
|
||||
|
||||
#### **従来の実装(最適化なし)**
|
||||
```mir
|
||||
; 非効率:毎回関数呼び出し
|
||||
%1 = ExternCall env.canvas.fillRect ["canvas", 10, 10, 100, 100, "red"]
|
||||
%2 = ExternCall env.canvas.fillRect ["canvas", 110, 10, 100, 100, "blue"]
|
||||
%3 = ExternCall env.canvas.fillRect ["canvas", 220, 10, 100, 100, "green"]
|
||||
```
|
||||
|
||||
#### **MIR最適化後(バッチ処理)**
|
||||
```mir
|
||||
; 効率化:バッチ処理
|
||||
%rects = ArrayConstruct [
|
||||
{x: 10, y: 10, w: 100, h: 100, color: "red"},
|
||||
{x: 110, y: 10, w: 100, h: 100, color: "blue"},
|
||||
{x: 220, y: 10, w: 100, h: 100, color: "green"}
|
||||
]
|
||||
%1 = ExternCall env.canvas.fillRectBatch ["canvas", %rects]
|
||||
```
|
||||
|
||||
#### **Effect Systemによる並列化**
|
||||
```mir
|
||||
; pure関数は並列実行可能
|
||||
%1 = BuiltinCall string.upper ["hello"] ; effect: pure
|
||||
%2 = BuiltinCall math.sin [3.14] ; effect: pure
|
||||
%3 = BuiltinCall string.lower ["WORLD"] ; effect: pure
|
||||
; ↑ これらは並列実行される
|
||||
|
||||
%4 = ExternCall env.console.log [%1] ; effect: io
|
||||
%5 = ExternCall env.console.log [%2] ; effect: io
|
||||
; ↑ これらは順序保持される
|
||||
```
|
||||
|
||||
### 🎯 バックエンド別最適化
|
||||
|
||||
#### **WASM最適化**
|
||||
```wasm
|
||||
;; BIDから自動生成された最適化WASM
|
||||
(func $optimized_canvas_batch
|
||||
(param $canvas_id i32) (param $canvas_id_len i32)
|
||||
(param $rects_ptr i32) (param $rect_count i32)
|
||||
|
||||
;; ループ展開による高速化
|
||||
(local $i i32)
|
||||
(local $rect_ptr i32)
|
||||
|
||||
loop $rect_loop
|
||||
;; 直接メモリアクセス(境界チェック済み)
|
||||
local.get $rect_ptr
|
||||
i32.load ;; x
|
||||
local.get $rect_ptr
|
||||
i32.load offset=4 ;; y
|
||||
;; ... 高速描画処理
|
||||
|
||||
local.get $rect_ptr
|
||||
i32.const 20
|
||||
i32.add
|
||||
local.set $rect_ptr
|
||||
|
||||
local.get $i
|
||||
i32.const 1
|
||||
i32.add
|
||||
local.tee $i
|
||||
local.get $rect_count
|
||||
i32.lt_u
|
||||
br_if $rect_loop
|
||||
end
|
||||
)
|
||||
```
|
||||
|
||||
#### **AOT最適化(LLVM IR)**
|
||||
```llvm
|
||||
; LLVM IRレベルでの最適化
|
||||
define void @optimized_image_processing(i8* %image_data, i32 %width, i32 %height) {
|
||||
entry:
|
||||
; ベクトル化された画像処理
|
||||
%0 = bitcast i8* %image_data to <16 x i8>*
|
||||
|
||||
; SIMD命令による並列処理
|
||||
br label %loop.header
|
||||
|
||||
loop.header:
|
||||
%i = phi i32 [ 0, %entry ], [ %i.next, %loop.body ]
|
||||
%cmp = icmp ult i32 %i, %height
|
||||
br i1 %cmp, label %loop.body, label %exit
|
||||
|
||||
loop.body:
|
||||
; 16ピクセル同時処理(AVX2/NEON活用)
|
||||
%pixel_ptr = getelementptr <16 x i8>, <16 x i8>* %0, i32 %i
|
||||
%pixels = load <16 x i8>, <16 x i8>* %pixel_ptr
|
||||
|
||||
; ベクトル化されたエッジ検出
|
||||
%edges = call <16 x i8> @vectorized_edge_detection(<16 x i8> %pixels)
|
||||
|
||||
store <16 x i8> %edges, <16 x i8>* %pixel_ptr
|
||||
|
||||
%i.next = add i32 %i, 1
|
||||
br label %loop.header
|
||||
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
```
|
||||
|
||||
## 🌟 革命的効果
|
||||
|
||||
### 🚀 開発者体験の向上
|
||||
- **学習コスト**: 一つの構文ですべてのAPIが使える
|
||||
- **IDE統合**: 全APIの統一補完・エラー検出
|
||||
- **デバッグ**: 統一エラーモデルによる一貫したデバッグ体験
|
||||
|
||||
### ⚡ パフォーマンス向上
|
||||
- **MIRレベル最適化**: すべてのAPIで同じ最適化技術
|
||||
- **Effect System**: 安全な並列化・順序最適化
|
||||
- **バックエンド最適化**: WASM/AOT固有の最適化
|
||||
|
||||
### 🌍 エコシステム拡大
|
||||
- **ライブラリ統合**: 既存C/Rustライブラリの簡単統合
|
||||
- **クロスプラットフォーム**: 同じコードが全環境で動作
|
||||
- **標準化**: BIDによる外部API標準化
|
||||
|
||||
---
|
||||
|
||||
**🎉 これが「なんでもAPI計画」の真の実力だにゃ!あらゆる開発が統一された美しい構文で実現できるにゃ!🚀🐱**
|
||||
@ -1,563 +0,0 @@
|
||||
# なんでもAPI計画:nyash.link × FFI-ABI × MIR 統合設計
|
||||
|
||||
## 🌟 革命的統合ビジョン
|
||||
|
||||
### 📊 現状把握
|
||||
- ✅ **nyash.linkシステム**: 標準関数・モジュール管理設計完了
|
||||
- ✅ **FFI-ABI仕様**: BID(Box Interface Definition)による外部API統一
|
||||
- ✅ **MIR ExternCall**: 外部関数呼び出しのMIRレベル実装
|
||||
- 🎯 **統合目標**: 3つのシステムを統合し「なんでもAPI」を実現
|
||||
|
||||
### 🚀 統合後の開発体験
|
||||
```nyash
|
||||
# === 単一のusing構文ですべてが使える! ===
|
||||
using nyashstd # 組み込み標準ライブラリ
|
||||
using console_api # ブラウザConsole API (FFI-ABI)
|
||||
using canvas_api # Canvas API (FFI-ABI)
|
||||
using opencv_api # OpenCV外部ライブラリ (FFI-ABI)
|
||||
using mylib # 自作Nyashモジュール
|
||||
|
||||
# 全部同じ記法で使える!
|
||||
string.upper("hello") # 組み込み標準ライブラリ
|
||||
console.log("Hello Nyash!") # ブラウザAPI
|
||||
canvas.fillRect("game", 10, 10, 80, 60, "red") # Canvas API
|
||||
opencv.loadImage("photo.jpg") # 外部ライブラリ
|
||||
mylib.processData("input") # 自作モジュール
|
||||
```
|
||||
|
||||
## 🏗️ 統合アーキテクチャ設計
|
||||
|
||||
### 1. 拡張nyash.link仕様
|
||||
|
||||
#### **依存関係タイプの統合**
|
||||
```toml
|
||||
# nyash.link - 全API統一管理
|
||||
[project]
|
||||
name = "awesome-nyash-app"
|
||||
version = "1.0.0"
|
||||
|
||||
[dependencies]
|
||||
# === 組み込み標準ライブラリ ===
|
||||
nyashstd = { builtin = true }
|
||||
|
||||
# === FFI-ABI経由外部API ===
|
||||
console_api = { bid = "./apis/console.yaml" }
|
||||
canvas_api = { bid = "./apis/canvas.yaml" }
|
||||
webgl_api = { bid = "./apis/webgl.yaml" }
|
||||
dom_api = { bid = "./apis/dom.yaml" }
|
||||
|
||||
# === システムライブラリ ===
|
||||
libc = { bid = "./apis/libc.yaml", library = "system" }
|
||||
math_lib = { bid = "./apis/math.yaml", library = "libm" }
|
||||
|
||||
# === 外部共有ライブラリ ===
|
||||
opencv = { bid = "./apis/opencv.yaml", library = "./libs/opencv.so" }
|
||||
sqlite = { bid = "./apis/sqlite.yaml", library = "./libs/sqlite.so" }
|
||||
|
||||
# === Nyashモジュール(従来通り) ===
|
||||
mylib = { path = "./src/mylib.hako" }
|
||||
utils = { path = "./src/utils.hako" }
|
||||
models = { path = "./src/models/" }
|
||||
|
||||
# === 将来の外部パッケージ ===
|
||||
# http_client = { version = "1.0.0", registry = "nyash-pkg" }
|
||||
|
||||
[build]
|
||||
entry_point = "./src/main.hako"
|
||||
backends = ["vm", "wasm", "aot"] # 対象バックエンド指定
|
||||
```
|
||||
|
||||
#### **BIDファイル例**
|
||||
```yaml
|
||||
# apis/console.yaml - Console API定義
|
||||
version: 0
|
||||
metadata:
|
||||
name: "Browser Console API"
|
||||
description: "Standard browser console interface"
|
||||
target_environments: ["browser", "node"]
|
||||
|
||||
interfaces:
|
||||
- name: console_api.console
|
||||
box: Console
|
||||
namespace: console_api
|
||||
methods:
|
||||
- name: log
|
||||
params: [ {string: message} ]
|
||||
returns: void
|
||||
effect: io
|
||||
description: "Output message to console"
|
||||
|
||||
- name: warn
|
||||
params: [ {string: message} ]
|
||||
returns: void
|
||||
effect: io
|
||||
|
||||
- name: error
|
||||
params: [ {string: message} ]
|
||||
returns: void
|
||||
effect: io
|
||||
|
||||
# apis/canvas.yaml - Canvas API定義
|
||||
version: 0
|
||||
interfaces:
|
||||
- name: canvas_api.canvas
|
||||
box: Canvas
|
||||
namespace: canvas_api
|
||||
methods:
|
||||
- name: fillRect
|
||||
params:
|
||||
- {string: canvas_id}
|
||||
- {i32: x}
|
||||
- {i32: y}
|
||||
- {i32: width}
|
||||
- {i32: height}
|
||||
- {string: color}
|
||||
returns: void
|
||||
effect: io
|
||||
|
||||
- name: fillText
|
||||
params:
|
||||
- {string: canvas_id}
|
||||
- {string: text}
|
||||
- {i32: x}
|
||||
- {i32: y}
|
||||
- {string: font}
|
||||
- {string: color}
|
||||
returns: void
|
||||
effect: io
|
||||
```
|
||||
|
||||
### 2. 統合名前空間レジストリ
|
||||
|
||||
#### **UniversalNamespaceRegistry設計**
|
||||
```rust
|
||||
// 新ファイル: src/registry/universal.rs
|
||||
use crate::stdlib::BuiltinStdlib;
|
||||
use crate::bid::BidDefinition;
|
||||
use crate::module::ExternalModule;
|
||||
|
||||
pub struct UniversalNamespaceRegistry {
|
||||
/// 組み込み標準ライブラリ
|
||||
builtin: Arc<BuiltinStdlib>,
|
||||
|
||||
/// FFI-ABI経由の外部API
|
||||
ffi_apis: HashMap<String, Arc<BidDefinition>>,
|
||||
|
||||
/// Nyashモジュール
|
||||
nyash_modules: HashMap<String, Arc<ExternalModule>>,
|
||||
|
||||
/// using imports(ファイル別)
|
||||
using_imports: Arc<RwLock<HashMap<String, UsingContext>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UsingContext {
|
||||
pub builtin_imports: Vec<String>, // ["nyashstd"]
|
||||
pub ffi_imports: Vec<String>, // ["console_api", "canvas_api"]
|
||||
pub module_imports: Vec<String>, // ["mylib", "utils"]
|
||||
pub file_id: String,
|
||||
}
|
||||
|
||||
impl UniversalNamespaceRegistry {
|
||||
pub fn new(nyash_link: &NyashLink) -> Result<Self, RegistryError> {
|
||||
let mut registry = UniversalNamespaceRegistry {
|
||||
builtin: Arc::new(BuiltinStdlib::new()),
|
||||
ffi_apis: HashMap::new(),
|
||||
nyash_modules: HashMap::new(),
|
||||
using_imports: Arc::new(RwLock::new(HashMap::new())),
|
||||
};
|
||||
|
||||
// nyash.linkからFFI-ABI定義読み込み
|
||||
registry.load_ffi_apis(nyash_link)?;
|
||||
|
||||
// Nyashモジュール読み込み
|
||||
registry.load_nyash_modules(nyash_link)?;
|
||||
|
||||
Ok(registry)
|
||||
}
|
||||
|
||||
/// 統合using文処理
|
||||
pub fn execute_using(&mut self, namespace_name: &str, file_id: &str)
|
||||
-> Result<(), RuntimeError> {
|
||||
|
||||
let context = self.using_imports
|
||||
.write().unwrap()
|
||||
.entry(file_id.to_string())
|
||||
.or_insert_with(|| UsingContext {
|
||||
builtin_imports: Vec::new(),
|
||||
ffi_imports: Vec::new(),
|
||||
module_imports: Vec::new(),
|
||||
file_id: file_id.to_string(),
|
||||
});
|
||||
|
||||
// 組み込み標準ライブラリ
|
||||
if self.builtin.has_namespace(namespace_name) {
|
||||
if !context.builtin_imports.contains(&namespace_name.to_string()) {
|
||||
context.builtin_imports.push(namespace_name.to_string());
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// FFI-ABI API
|
||||
if self.ffi_apis.contains_key(namespace_name) {
|
||||
if !context.ffi_imports.contains(&namespace_name.to_string()) {
|
||||
context.ffi_imports.push(namespace_name.to_string());
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Nyashモジュール
|
||||
if self.hako_modules.contains_key(namespace_name) {
|
||||
if !context.module_imports.contains(&namespace_name.to_string()) {
|
||||
context.module_imports.push(namespace_name.to_string());
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Err(RuntimeError::UndefinedNamespace(namespace_name.to_string()))
|
||||
}
|
||||
|
||||
/// 統合関数解決
|
||||
pub fn resolve_call(&self, file_id: &str, path: &[String])
|
||||
-> Result<CallTarget, RuntimeError> {
|
||||
|
||||
if path.len() != 2 {
|
||||
return Err(RuntimeError::InvalidQualifiedName(path.join(".")));
|
||||
}
|
||||
|
||||
let box_name = &path[0];
|
||||
let method_name = &path[1];
|
||||
|
||||
if let Ok(imports) = self.using_imports.read() {
|
||||
if let Some(context) = imports.get(file_id) {
|
||||
|
||||
// 1. 組み込み標準ライブラリ検索
|
||||
for namespace in &context.builtin_imports {
|
||||
if let Some(target) = self.builtin.resolve_call(namespace, box_name, method_name) {
|
||||
return Ok(CallTarget::Builtin(target));
|
||||
}
|
||||
}
|
||||
|
||||
// 2. FFI-ABI API検索
|
||||
for namespace in &context.ffi_imports {
|
||||
if let Some(bid) = self.ffi_apis.get(namespace) {
|
||||
if let Some(target) = bid.resolve_method(box_name, method_name) {
|
||||
return Ok(CallTarget::FfiAbi(target));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Nyashモジュール検索
|
||||
for namespace in &context.module_imports {
|
||||
if let Some(module) = self.hako_modules.get(namespace) {
|
||||
if let Some(target) = module.resolve_method(box_name, method_name) {
|
||||
return Ok(CallTarget::NyashModule(target));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(RuntimeError::UndefinedMethod(format!("{}.{}", box_name, method_name)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CallTarget {
|
||||
Builtin(BuiltinMethodTarget),
|
||||
FfiAbi(FfiMethodTarget),
|
||||
NyashModule(NyashMethodTarget),
|
||||
}
|
||||
```
|
||||
|
||||
### 3. MIRレベル統合
|
||||
|
||||
#### **MIR命令拡張**
|
||||
```rust
|
||||
// src/mir/instruction.rs拡張
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum MirInstruction {
|
||||
// 既存命令...
|
||||
|
||||
// === 統合関数呼び出し ===
|
||||
|
||||
/// 組み込み標準ライブラリ呼び出し
|
||||
BuiltinCall {
|
||||
target: String, // "string.upper"
|
||||
args: Vec<ValueId>,
|
||||
result: ValueId,
|
||||
effect: Effect,
|
||||
},
|
||||
|
||||
/// FFI-ABI外部API呼び出し
|
||||
ExternCall {
|
||||
interface: String, // "console_api.console"
|
||||
method: String, // "log"
|
||||
args: Vec<ValueId>,
|
||||
result: Option<ValueId>,
|
||||
effect: Effect,
|
||||
bid_signature: BidMethodSignature,
|
||||
},
|
||||
|
||||
/// Nyashモジュール関数呼び出し
|
||||
ModuleCall {
|
||||
module: String, // "mylib"
|
||||
function: String, // "processData"
|
||||
args: Vec<ValueId>,
|
||||
result: ValueId,
|
||||
effect: Effect,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Effect {
|
||||
Pure, // 副作用なし、並び替え可能
|
||||
Mut, // 同リソース内で順序保持
|
||||
Io, // プログラム順序保持
|
||||
Control, // 制御フロー影響
|
||||
}
|
||||
```
|
||||
|
||||
#### **MIR生成統合**
|
||||
```rust
|
||||
// src/mir/builder.rs拡張
|
||||
impl MirBuilder {
|
||||
pub fn build_unified_call(&mut self, target: CallTarget, args: Vec<ValueId>)
|
||||
-> Result<ValueId, MirError> {
|
||||
|
||||
match target {
|
||||
CallTarget::Builtin(builtin_target) => {
|
||||
let result = self.new_value_id();
|
||||
self.emit(MirInstruction::BuiltinCall {
|
||||
target: builtin_target.qualified_name(),
|
||||
args,
|
||||
result,
|
||||
effect: builtin_target.effect(),
|
||||
});
|
||||
Ok(result)
|
||||
},
|
||||
|
||||
CallTarget::FfiAbi(ffi_target) => {
|
||||
let result = if ffi_target.returns_void() {
|
||||
None
|
||||
} else {
|
||||
Some(self.new_value_id())
|
||||
};
|
||||
|
||||
self.emit(MirInstruction::ExternCall {
|
||||
interface: ffi_target.interface_name(),
|
||||
method: ffi_target.method_name(),
|
||||
args,
|
||||
result,
|
||||
effect: ffi_target.effect(),
|
||||
bid_signature: ffi_target.signature().clone(),
|
||||
});
|
||||
|
||||
result.ok_or(MirError::VoidReturn)
|
||||
},
|
||||
|
||||
CallTarget::NyashModule(module_target) => {
|
||||
let result = self.new_value_id();
|
||||
self.emit(MirInstruction::ModuleCall {
|
||||
module: module_target.module_name(),
|
||||
function: module_target.function_name(),
|
||||
args,
|
||||
result,
|
||||
effect: Effect::Io, // デフォルト
|
||||
});
|
||||
Ok(result)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. バックエンド統合実装
|
||||
|
||||
#### **VM実行統合**
|
||||
```rust
|
||||
// src/backend/vm.rs拡張
|
||||
impl VmBackend {
|
||||
pub fn execute_instruction(&mut self, instr: &MirInstruction)
|
||||
-> Result<(), VmError> {
|
||||
|
||||
match instr {
|
||||
MirInstruction::BuiltinCall { target, args, result, .. } => {
|
||||
let evaluated_args = self.evaluate_args(args)?;
|
||||
let output = self.builtin_executor.call(target, evaluated_args)?;
|
||||
self.set_value(*result, output);
|
||||
Ok(())
|
||||
},
|
||||
|
||||
MirInstruction::ExternCall { interface, method, args, result, bid_signature, .. } => {
|
||||
// VM環境ではスタブ実装
|
||||
let evaluated_args = self.evaluate_args(args)?;
|
||||
let output = self.extern_stub.call(interface, method, evaluated_args, bid_signature)?;
|
||||
if let Some(res_id) = result {
|
||||
self.set_value(*res_id, output);
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
|
||||
MirInstruction::ModuleCall { module, function, args, result, .. } => {
|
||||
let evaluated_args = self.evaluate_args(args)?;
|
||||
let output = self.module_executor.call(module, function, evaluated_args)?;
|
||||
self.set_value(*result, output);
|
||||
Ok(())
|
||||
},
|
||||
|
||||
// 既存命令処理...
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **WASM生成統合**
|
||||
```rust
|
||||
// src/backend/wasm/codegen.rs拡張
|
||||
impl WasmCodegen {
|
||||
pub fn generate_instruction(&mut self, instr: &MirInstruction)
|
||||
-> Result<(), WasmError> {
|
||||
|
||||
match instr {
|
||||
MirInstruction::BuiltinCall { target, args, result, .. } => {
|
||||
// 組み込み関数は直接実装
|
||||
self.generate_builtin_call(target, args, *result)
|
||||
},
|
||||
|
||||
MirInstruction::ExternCall { interface, method, args, bid_signature, .. } => {
|
||||
// BIDから自動生成されたWASM import呼び出し
|
||||
let import_name = format!("{}_{}",
|
||||
interface.replace(".", "_"),
|
||||
method
|
||||
);
|
||||
|
||||
self.generate_extern_call(&import_name, args, bid_signature)
|
||||
},
|
||||
|
||||
MirInstruction::ModuleCall { module, function, args, result, .. } => {
|
||||
// 内部関数呼び出し
|
||||
let function_name = format!("{}_{}", module, function);
|
||||
self.generate_function_call(&function_name, args, *result)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// BIDからWASM RuntimeImports自動生成
|
||||
pub fn generate_runtime_imports(&mut self, bid_definitions: &[BidDefinition])
|
||||
-> Result<String, WasmError> {
|
||||
|
||||
let mut imports = String::new();
|
||||
|
||||
for bid in bid_definitions {
|
||||
for interface in &bid.interfaces {
|
||||
for method in &interface.methods {
|
||||
let import_name = format!("{}_{}",
|
||||
interface.name.replace(".", "_"),
|
||||
method.name
|
||||
);
|
||||
|
||||
let signature = self.bid_to_wasm_signature(&method.params, &method.returns)?;
|
||||
imports.push_str(&format!(
|
||||
"(import \"env\" \"{}\" {})\n",
|
||||
import_name, signature
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(imports)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **AOT生成統合**
|
||||
```rust
|
||||
// src/backend/aot/compiler.rs拡張
|
||||
impl AotCompiler {
|
||||
pub fn compile_instruction(&mut self, instr: &MirInstruction)
|
||||
-> Result<(), AotError> {
|
||||
|
||||
match instr {
|
||||
MirInstruction::ExternCall { interface, method, args, bid_signature, .. } => {
|
||||
// LLVM IR外部関数宣言生成
|
||||
let extern_func_name = format!("{}_{}",
|
||||
interface.replace(".", "_"),
|
||||
method
|
||||
);
|
||||
|
||||
let signature = self.bid_to_llvm_signature(bid_signature)?;
|
||||
self.declare_external_function(&extern_func_name, &signature)?;
|
||||
self.generate_call(&extern_func_name, args)?;
|
||||
|
||||
Ok(())
|
||||
},
|
||||
|
||||
// その他の命令処理...
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🎯 段階的実装戦略
|
||||
|
||||
### Phase 0: 基盤統合(2-3週間)
|
||||
1. **UniversalNamespaceRegistry実装** - 全API統一管理
|
||||
2. **nyash.link拡張** - BID依存関係サポート
|
||||
3. **統合using文** - 3種類のAPI統一インポート
|
||||
|
||||
### Phase 1: FFI-ABI統合(3-4週間)
|
||||
1. **BID読み込み機能** - YAML解析・検証
|
||||
2. **MIR ExternCall統合** - FFI-ABI→MIR変換
|
||||
3. **WASM RuntimeImports自動生成** - BID→WASM import
|
||||
|
||||
### Phase 2: 完全統合(4-6週間)
|
||||
1. **全バックエンド対応** - VM/WASM/AOT統合実装
|
||||
2. **エラーハンドリング統合** - 統一エラーモデル
|
||||
3. **パフォーマンス最適化** - 高速名前解決
|
||||
|
||||
## 🧪 統合テスト戦略
|
||||
|
||||
### 基本統合テスト
|
||||
```nyash
|
||||
# test_universal_integration.hako
|
||||
using nyashstd
|
||||
using console_api
|
||||
using mylib
|
||||
|
||||
# 3種類のAPIが同じように使える
|
||||
assert(string.upper("test") == "TEST") # 組み込み
|
||||
console.log("Integration test successful") # FFI-ABI
|
||||
assert(mylib.process("data") == "processed") # Nyash
|
||||
```
|
||||
|
||||
### FFI-ABI統合テスト
|
||||
```nyash
|
||||
# test_ffi_abi_integration.hako
|
||||
using canvas_api
|
||||
|
||||
# Canvas API経由での描画
|
||||
canvas.fillRect("game-canvas", 10, 10, 100, 100, "red")
|
||||
canvas.fillText("game-canvas", "Score: 100", 10, 30, "16px Arial", "white")
|
||||
```
|
||||
|
||||
## 🌟 期待される革命的効果
|
||||
|
||||
### 🚀 開発者体験
|
||||
- **統一API**: 組み込み・外部・自作すべて同じ書き方
|
||||
- **IDE補完**: すべてのAPIが`ny`で補完される
|
||||
- **エラー処理**: 統一エラーモデルで一貫性
|
||||
|
||||
### 🏗️ アーキテクチャ
|
||||
- **MIRレベル統合**: 全バックエンドで同じパフォーマンス最適化
|
||||
- **Effect System**: pure/mut/io/controlによる安全性保証
|
||||
- **言語非依存**: BIDによる外部ライブラリ標準化
|
||||
|
||||
### 🌍 エコシステム
|
||||
- **なんでもAPI**: あらゆる外部ライブラリがNyashから使える
|
||||
- **バックエンド統一**: 同じコードがVM/WASM/AOTで動作
|
||||
- **将来拡張**: パッケージレジストリでBID共有
|
||||
|
||||
---
|
||||
|
||||
**🎉 この統合設計で、Nyashが真に「なんでもできる」モダン言語になるにゃ!🚀🐱**
|
||||
@ -1,106 +0,0 @@
|
||||
# Phase 195: Pattern 4 (Loop with Continue) Implementation Plan
|
||||
|
||||
**Status**: Deferred (not yet implemented)
|
||||
|
||||
## Overview
|
||||
|
||||
Pattern 4 handles loops with `continue` statements that skip to the next iteration. This is the most complex loop pattern due to additional control flow requirements.
|
||||
|
||||
## Why Deferred?
|
||||
|
||||
1. **Continue semantics require additional PHI and control flow analysis**
|
||||
- Continue creates an additional edge to the loop header
|
||||
- Requires phi nodes for both continue and normal paths
|
||||
- More complex than break (which exits the loop)
|
||||
|
||||
2. **Pattern 3 covers most practical cases**
|
||||
- Pattern 1: Simple while loops
|
||||
- Pattern 2: Loops with break
|
||||
- Pattern 3: Loops with if + PHI (most common complex pattern)
|
||||
- Pattern 4: Loops with continue (less common in practice)
|
||||
|
||||
3. **Lower priority than break/if patterns**
|
||||
- Break patterns (Pattern 2) are more common
|
||||
- If + PHI patterns (Pattern 3) handle complex control flow
|
||||
- Continue can often be refactored using if statements
|
||||
|
||||
## Example Use Case
|
||||
|
||||
```nyash
|
||||
local i = 0
|
||||
local sum = 0
|
||||
loop(i < 10) {
|
||||
i = i + 1
|
||||
if (i % 2 == 0) {
|
||||
continue // Skip even numbers
|
||||
}
|
||||
sum = sum + i
|
||||
}
|
||||
// sum = 25 (1+3+5+7+9)
|
||||
```
|
||||
|
||||
## Implementation Requirements
|
||||
|
||||
When implemented, Pattern 4 lowering will need to:
|
||||
|
||||
1. **Detect continue statements** in the loop body
|
||||
2. **Generate PHI nodes** for continue target (loop header)
|
||||
3. **Handle carrier variables** (i, sum) across continue boundaries
|
||||
4. **Generate exit PHI nodes** for final values after loop
|
||||
|
||||
## Control Flow Diagram
|
||||
|
||||
```
|
||||
header
|
||||
|
|
||||
v
|
||||
body
|
||||
|
|
||||
/----+----\
|
||||
/ \
|
||||
v v
|
||||
continue normal
|
||||
| |
|
||||
\-----+-------/
|
||||
|
|
||||
v
|
||||
latch
|
||||
|
|
||||
/---+---\
|
||||
/ \
|
||||
v v
|
||||
loop exit
|
||||
```
|
||||
|
||||
## Workaround
|
||||
|
||||
Until Pattern 4 is implemented, use Pattern 3 (if + PHI) instead:
|
||||
|
||||
```nyash
|
||||
local i = 0
|
||||
local sum = 0
|
||||
loop(i < 10) {
|
||||
i = i + 1
|
||||
if (not (i % 2 == 0)) { // Invert condition
|
||||
sum = sum + i
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Migration Path
|
||||
|
||||
1. **Pattern 1**: Simple while loops (no break/continue)
|
||||
2. **Pattern 2**: Loops with break
|
||||
3. **Pattern 3**: Loops with if + PHI
|
||||
4. **Pattern 4**: (FUTURE) Loops with continue statements
|
||||
|
||||
## Related Files
|
||||
|
||||
- `src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs` - Stub implementation
|
||||
- `src/mir/join_ir/lowering/loop_with_continue_minimal.rs` - Lowering logic (TODO)
|
||||
|
||||
## Timeline
|
||||
|
||||
- Phase 195+: Implementation planned but deferred
|
||||
- Priority: Lower than Pattern 1-3
|
||||
- Complexity: High (additional control flow edges)
|
||||
@ -1,74 +0,0 @@
|
||||
# Scope Reuse Blocks (MVP Proposal)
|
||||
|
||||
Status: design-only during the feature‑pause (no implementation)
|
||||
|
||||
Summary
|
||||
- Give short, reusable logic a name within the current scope without promoting it to a top-level function.
|
||||
- Keep the core small: block body + postfix header sugar; desugar to local function + normal calls.
|
||||
- Zero runtime cost: lowers to let/if/call/ret only (no new instructions/closures).
|
||||
|
||||
Syntax (postfix header; Nyash style)
|
||||
- Block form (multi-statement):
|
||||
```nyash
|
||||
{ /* BODY */ } scope name(arglist?) (-> Ret)?
|
||||
// call within the same scope
|
||||
name(args)
|
||||
```
|
||||
- Expression form (one-liner):
|
||||
```nyash
|
||||
=> EXPR scope name(arglist?) (-> Ret)?
|
||||
```
|
||||
|
||||
Semantics
|
||||
- Visibility: `name` is local to the defining scope; not exported.
|
||||
- Capture: by reference by default. Mutating captured vars requires explicit `mut` on those bindings.
|
||||
- Recursion: disallowed in MVP (can be lifted later).
|
||||
- Errors/exits: same as regular functions (return/cleanup/catch apply at the function boundary).
|
||||
|
||||
Lowering (desugaring)
|
||||
- Transform into a local function plus a local binding for convenience calls.
|
||||
```nyash
|
||||
// { BODY } scope check(a:Int)->Str
|
||||
// ↓ (conceptual)
|
||||
let __cap_me = me; let __cap_locals = { /* needed refs */ };
|
||||
method __scope_check__(a:Int)->Str {
|
||||
return BODY
|
||||
}
|
||||
let check = (x) => __scope_check__(x)
|
||||
```
|
||||
- Captures are passed via hidden arguments or an environment box; no new VM opcodes.
|
||||
|
||||
Examples
|
||||
```nyash
|
||||
{ if x % 2 == 0 { return "even" } return "odd" } scope parity(x:Int)->StringBox
|
||||
|
||||
for i in range(0,10) {
|
||||
print(parity(i))
|
||||
}
|
||||
```
|
||||
|
||||
Safety rules (MVP)
|
||||
- Capture: read-only by default; writes allowed only when the captured binding is declared `mut`.
|
||||
- Name uniqueness: `scope name` must be unique within the scope.
|
||||
- No cross-scope escape: values may be returned but the function reference itself is not exported.
|
||||
|
||||
Observability & Tooling
|
||||
- Add trace toggles (design only):
|
||||
- `NYASH_SCOPE_TRACE=1|json` to emit enter/exit and capture lists as JSONL.
|
||||
- Example: `{ "ev":"enter","sid":42,"caps":["me","cfg","mut total"] }`.
|
||||
- Lints (design only):
|
||||
- Single-use scope → suggest inline.
|
||||
- Excess captures → suggest narrowing.
|
||||
|
||||
Interactions
|
||||
- Works with guard/with/await sugars (it’s just a call).
|
||||
- Compatible with ASI and postfix aesthetics; no new top-level keywords beyond `scope` suffix.
|
||||
|
||||
Tests (syntax-only smokes; design)
|
||||
- scope_basic: called twice → same result.
|
||||
- scope_capture_read: reads `me/foo`.
|
||||
- scope_capture_mut: mutation only allowed when `mut` is present.
|
||||
- scope_with_catch_cleanup: postfix catch/cleanup applied at local-function boundary.
|
||||
|
||||
Pause note
|
||||
- This is documentation and design intent only. Implementation is deferred until after the feature‑pause (post‑bootstrap).
|
||||
@ -1,629 +0,0 @@
|
||||
# Stage1セルフホスティング起動アーキテクチャ改善提案
|
||||
|
||||
## 📋 エグゼクティブサマリー
|
||||
|
||||
Nyashのセルフホスティング実装で、Stage0(Rust)→ Stage1(.hako script)の起動が**環境変数25個**と**3つの引数経路**で複雑化している問題を整理し、業界標準パターンに基づいた改善案を提示する。
|
||||
|
||||
**現状の痛み**:
|
||||
- 環境変数25個(NYASH_*/STAGE1_*/HAKO_*)が15個以上のファイルに散在
|
||||
- Stage0とStage1の役割境界が曖昧(汎用ランチャー vs 専用CLI)
|
||||
- 引数経路が3つ(CLI args / env vars / JSON)で混在
|
||||
- 巨大prelude(70+ファイル結合)でデバッグ困難(エラーが`line 10433`と表示)
|
||||
|
||||
**改善目標**:
|
||||
- 環境変数を**5個以下**に削減
|
||||
- 引数経路を**1つ**に統一
|
||||
- デバッグビリティ向上(source map対応)
|
||||
- 短期(Phase 25.2)と長期(Phase 26+)の段階実装
|
||||
|
||||
---
|
||||
|
||||
## 🔍 A. 他言語の事例調査
|
||||
|
||||
### A-1. Rustコンパイラのブートストラップ(3段階明確化)
|
||||
|
||||
**アーキテクチャ**:
|
||||
```
|
||||
Stage 0: 事前ビルド済みベータ版rustc(CI artifactsからダウンロード)
|
||||
↓
|
||||
Stage 1: Stage0でビルドしたrustc + 標準ライブラリ(機能完全)
|
||||
↓
|
||||
Stage 2: Stage1で再ビルドしたrustc(検証用・本番利用)
|
||||
↓
|
||||
Stage 3: Stage2で再ビルドしたrustc(完全自己再現性検証)
|
||||
```
|
||||
|
||||
**特徴**:
|
||||
- **明確な責務分離**: Stage0は「ビルドツール」、Stage1以降は「開発コンパイラ」
|
||||
- **環境変数最小**: `RUSTC_BOOTSTRAP`など**4個のみ**
|
||||
- **CLI引数優先**: 環境変数はビルドシステム内部のみ、ユーザーは`x build --stage N`でシンプル操作
|
||||
- **2024年改善**: Stage0でstdも事前ビルド版を使用し、`cfg(bootstrap)`を削除(複雑性削減)
|
||||
|
||||
**参考**: [Rust Compiler Development Guide - Bootstrapping](https://rustc-dev-guide.rust-lang.org/building/bootstrapping/what-bootstrapping-does.html)
|
||||
|
||||
---
|
||||
|
||||
### A-2. Goコンパイラのブートストラップ(段階自動化)
|
||||
|
||||
**アーキテクチャ**:
|
||||
```
|
||||
Bootstrap Compiler: Go 1.N-2(最小2バージョン前)
|
||||
↓
|
||||
cmd/dist: ブートストラップビルドツール(Go製)
|
||||
↓
|
||||
Toolchain1 → Toolchain2 → Toolchain3(自動多段階ビルド)
|
||||
```
|
||||
|
||||
**特徴**:
|
||||
- **自動段階切り替え**: `cmd/dist`が段階を自動制御、ユーザーは意識不要
|
||||
- **環境変数ゼロ**: すべてCLI引数で制御(`GOROOT`, `GOPATH`のみ)
|
||||
- **最適化重視**: 無関係アーキテクチャ向けファイルはダミー化(6秒短縮)
|
||||
- **バージョンポリシー明確**: 1.24/1.25は1.22が必須(N-2ルール)
|
||||
|
||||
**参考**: [How Go uses Go to build itself](https://dave.cheney.net/2013/06/04/how-go-uses-go-to-build-itself)
|
||||
|
||||
---
|
||||
|
||||
### A-3. Nimコンパイラのブートストラップ(C経由2段階)
|
||||
|
||||
**アーキテクチャ**:
|
||||
```
|
||||
csources_v3: C言語生成コード(Nim古バージョンから生成)
|
||||
↓
|
||||
koch.nim: ブートストラップツール
|
||||
↓
|
||||
Nim Compiler v1: 完全機能版
|
||||
↓
|
||||
Nim Compiler v2: 自己再ビルド版(検証)
|
||||
```
|
||||
|
||||
**特徴**:
|
||||
- **Cソース安定化**: `csources_v3`リポジトリで分離管理
|
||||
- **ツール一本化**: `koch`が「ビルド・テスト・ドキュメント生成」すべて担当
|
||||
- **環境変数なし**: すべて`koch`のサブコマンドで制御
|
||||
- **2024年改革**: NIR中間言語導入で、フロントエンド複数バージョン対応予定
|
||||
|
||||
**参考**: [Nim GitHub - Internals](https://nim-lang.org/docs/intern.html)
|
||||
|
||||
---
|
||||
|
||||
### A-4. 設定管理の業界標準パターン
|
||||
|
||||
**優先度階層(POSIX標準準拠)**:
|
||||
```
|
||||
1. CLI引数(最優先) ← ユーザーの明示的意図
|
||||
2. 環境変数 ← セッション固有設定
|
||||
3. ローカル設定ファイル ← プロジェクト設定
|
||||
4. グローバル設定ファイル ← システム設定
|
||||
5. デフォルト値(最低優先)
|
||||
```
|
||||
|
||||
**設計原則**(ASP.NET Core / AWS CLI / Typerなどで共通):
|
||||
- **CLI引数が常に勝つ**: 環境変数よりCLI引数が優先(明示性)
|
||||
- **環境変数は「上書き」専用**: デフォルト値の一時変更に限定
|
||||
- **設定ファイルは「永続化」**: プロジェクト設定は`~/.config`や`.toml`に
|
||||
- **Chain of Responsibility**: 見つかるまで順に探索、最後に見つかった値が勝つ
|
||||
|
||||
**参考**: [Stack Overflow - Configuration Precedence](https://stackoverflow.com/questions/11077223/what-order-of-reading-configuration-values)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 B. Nyash向け具体的改善案
|
||||
|
||||
### B-1. 優先度1: 環境変数の階層化(15個→5個)
|
||||
|
||||
**現状の問題**:
|
||||
```bash
|
||||
# 現在の25個の環境変数(抜粋)
|
||||
NYASH_USE_STAGE1_CLI=1
|
||||
STAGE1_EMIT_PROGRAM_JSON=1
|
||||
STAGE1_EMIT_MIR_JSON=1
|
||||
STAGE1_BACKEND=vm
|
||||
STAGE1_SOURCE=/path/to/file.hako
|
||||
STAGE1_PROGRAM_JSON=/path/to/prog.json
|
||||
STAGE1_SOURCE_TEXT="..."
|
||||
STAGE1_CLI_ENTRY=/path/to/cli.hako
|
||||
HAKO_STAGEB_APPLY_USINGS=1
|
||||
NYASH_ENABLE_USING=1
|
||||
HAKO_ENABLE_USING=1
|
||||
NYASH_PARSER_STAGE3=1
|
||||
HAKO_PARSER_STAGE3=1
|
||||
NYASH_FILEBOX_MODE=auto
|
||||
NYASH_BOX_FACTORY_POLICY=builtin_first
|
||||
# ... さらに10個以上
|
||||
```
|
||||
|
||||
**改善後(5個に集約)**:
|
||||
```bash
|
||||
# 1. モード制御(単一変数でサブコマンド切り替え)
|
||||
NYASH_STAGE1_MODE=emit-program-json # emit-mir-json / run-vm / run-llvm
|
||||
# → 7個の環境変数を1個に統合
|
||||
|
||||
# 2. 入力ソース(パスまたはインライン)
|
||||
NYASH_STAGE1_INPUT=/path/to/source.hako # または STDIN: "-"
|
||||
# → STAGE1_SOURCE / STAGE1_SOURCE_TEXT / STAGE1_INPUT を統合
|
||||
|
||||
# 3. 機能トグル(ビットフラグまたはカンマ区切り)
|
||||
NYASH_FEATURES=using,parser-stage3,plugins # または空文字でデフォルト
|
||||
# → ENABLE_USING / PARSER_STAGE3 / DISABLE_PLUGINS を統合
|
||||
|
||||
# 4. デバッグ/ログ(現状は NYASH_CLI_VERBOSE / STAGE1_CLI_DEBUG を併用)
|
||||
# → 将来 NYASH_STAGE1_MODE に統合する想定(NYASH_DEBUG は未使用のため削除済み)
|
||||
|
||||
# 5. ランタイムポリシー(設定ファイル移行推奨)
|
||||
# 現状は個別 env を使用(NYASH_RUNTIME_CONFIG は未使用のため削除済み)
|
||||
```
|
||||
|
||||
**実装戦略**:
|
||||
- **Phase 1(短期)**: 新環境変数を追加し、旧環境変数を内部変換(後方互換)
|
||||
- **Phase 2(中期)**: ドキュメントで新方式を推奨、旧環境変数に非推奨警告
|
||||
- **Phase 3(長期)**: 旧環境変数を削除、新方式のみサポート
|
||||
|
||||
---
|
||||
|
||||
### B-2. 優先度2: アーキテクチャ統一(役割明確化)
|
||||
|
||||
**現状の問題**:
|
||||
- Stage0(Rust): 汎用ランチャー(`Main.main` / `main` を探す)
|
||||
- Stage1(.hako): 専用CLI(`stage1_cli emit program-json ...`)
|
||||
- 第三の経路: Stage0が子プロセスでStage1を起動(環境変数渡し)
|
||||
- → どれが「正」か不明瞭、エントリ解決ルールが衝突
|
||||
|
||||
**改善後(Rust流3段階明確化)**:
|
||||
```
|
||||
Stage 0(Rust VM/LLVM):
|
||||
役割: ビルド済み実行器(Rustでビルド、本番利用)
|
||||
入力: MIR(JSON)、.hako(パーサー組み込み)
|
||||
出力: 実行結果、オブジェクトファイル
|
||||
制約: セルフホスト不要、安定版として配布
|
||||
|
||||
Stage 1(.hako script - UsingResolver + MirBuilder):
|
||||
役割: セルフホスト開発コンパイラ(Stage0で実行)
|
||||
入力: .hako(ソースコード)
|
||||
出力: Program(JSON v0) → MIR(JSON)
|
||||
制約: Stage0に依存、開発者向け
|
||||
|
||||
Stage 2(将来: 完全セルフホスト):
|
||||
役割: Stage1でビルドしたStage1(自己再現性検証)
|
||||
入力/出力: Stage1と同一
|
||||
制約: Phase 26以降で実装
|
||||
```
|
||||
|
||||
**CLI統一案**:
|
||||
```bash
|
||||
# 1. 本番利用(Stage0直接実行)- 現状維持
|
||||
nyash program.hako # Rust VMで直接実行
|
||||
nyash --backend llvm prog.hako # LLVM AOTコンパイル
|
||||
|
||||
# 2. セルフホスト開発(Stage1経由)- 新CLI
|
||||
nyash --stage1 emit program-json source.hako > program.json
|
||||
nyash --stage1 emit mir-json source.hako > mir.json
|
||||
nyash --stage1 run --backend vm source.hako
|
||||
|
||||
# 3. 検証用(Stage2自己ビルド)- 将来拡張
|
||||
nyash --stage2 build stage1_compiler.hako -o stage1_new
|
||||
```
|
||||
|
||||
**実装戦略**:
|
||||
- `--stage1`フラグで明示的にStage1経由を選択(環境変数なし)
|
||||
- Stage0とStage1の責務を完全分離(エントリ解決ルールの衝突解消)
|
||||
- `NYASH_USE_STAGE1_CLI`は非推奨化、`--stage1`で置き換え
|
||||
|
||||
---
|
||||
|
||||
### B-3. 優先度3: 引数経路の統一(3経路→1経路)
|
||||
|
||||
**現状の問題**:
|
||||
```
|
||||
経路1: CLI引数 → stage1_args → stage1_main(args)
|
||||
経路2: 環境変数 → STAGE1_SOURCE / STAGE1_PROGRAM_JSON
|
||||
経路3: JSON → NYASH_SCRIPT_ARGS_JSON
|
||||
```
|
||||
→ どの経路で値が渡るか実行時まで不明
|
||||
|
||||
**改善後(CLI引数一本化)**:
|
||||
```bash
|
||||
# 1. サブコマンド形式(Git/Cargo風)
|
||||
nyash stage1 emit program-json source.hako
|
||||
nyash stage1 emit mir-json source.hako
|
||||
nyash stage1 run --backend vm source.hako -- arg1 arg2
|
||||
|
||||
# 2. 引数の優先度階層(業界標準)
|
||||
CLI引数 > 環境変数 > nyash.toml > デフォルト値
|
||||
|
||||
# 3. 環境変数は「一時上書き」のみ
|
||||
NYASH_STAGE1_MODE=emit-program-json nyash source.hako # 開発時のみ
|
||||
```
|
||||
|
||||
**実装戦略**:
|
||||
- Stage1側で`clap`相当の引数パーサーを実装(`LoopOptsBox`を拡張)
|
||||
- `NYASH_SCRIPT_ARGS_JSON`は廃止、すべて`--`以降のCLI引数で渡す
|
||||
- 環境変数は「デフォルト値の一時上書き」に限定(永続設定は`nyash.toml`へ)
|
||||
|
||||
---
|
||||
|
||||
### B-4. 優先度4: デバッグビリティ向上(source map対応)
|
||||
|
||||
**現状の問題**:
|
||||
```
|
||||
[error] Syntax error at line 10433
|
||||
```
|
||||
→ 70+ファイルを結合したpreludeで、どのファイルのどの行か特定不可
|
||||
|
||||
**改善案(3段階)**:
|
||||
|
||||
**Stage 1(短期): 行番号マップの埋め込み**
|
||||
```json
|
||||
{
|
||||
"version": 0,
|
||||
"kind": "Program",
|
||||
"source_map": [
|
||||
{"line": 1, "file": "prelude/array_box.hako", "orig_line": 1},
|
||||
{"line": 50, "file": "prelude/string_box.hako", "orig_line": 1},
|
||||
{"line": 150, "file": "user/main.hako", "orig_line": 1}
|
||||
],
|
||||
"body": [...]
|
||||
}
|
||||
```
|
||||
- Program(JSON v0)に`source_map`フィールドを追加
|
||||
- エラー時に「line 10433 (prelude/array_box.hako:42)」と表示
|
||||
|
||||
**Stage 2(中期): Source Map v3形式**
|
||||
```json
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["prelude/array_box.hako", "main.hako"],
|
||||
"mappings": "AAAA,CAAC;AAAD,CAAC...",
|
||||
"sourcesContent": ["...", "..."]
|
||||
}
|
||||
```
|
||||
- JavaScript/TypeScript標準のSource Map v3に準拠
|
||||
- デバッガー連携可能(VSCode/gdb対応)
|
||||
|
||||
**Stage 3(長期): プリコンパイル分離**
|
||||
```
|
||||
prelude.hako (70ファイル)
|
||||
↓ 事前コンパイル
|
||||
prelude.mir (MIRバイナリ)
|
||||
↓ リンク
|
||||
user_program.mir + prelude.mir → final.exe
|
||||
```
|
||||
- プリコンパイル済みプレリュードを配布(起動高速化)
|
||||
- ユーザーコードのみパース(エラー箇所明確化)
|
||||
|
||||
**実装戦略**:
|
||||
- Phase 25.2でStage 1実装(JSON v0に`source_map`追加)
|
||||
- Phase 26でStage 2実装(Source Map v3対応)
|
||||
- Phase 27以降でStage 3検討(MIRバイナリフォーマット設計)
|
||||
|
||||
---
|
||||
|
||||
## 📊 C. 優先順位と実装ロードマップ
|
||||
|
||||
### C-1. 短期解決(Phase 25.2: 今すぐできる)
|
||||
|
||||
**目標**: 開発者の混乱を即座に解消
|
||||
|
||||
**タスク**:
|
||||
1. **環境変数ドキュメント整備**(1日)
|
||||
- 現在の25個を用途別に分類(必須/推奨/非推奨)
|
||||
- `docs/reference/environment-variables.md`作成
|
||||
- 各変数の相互作用を図解
|
||||
|
||||
2. **デバッグ用ヘルパースクリプト**(2日)
|
||||
- `tools/stage1_debug.sh`: 環境変数を自動設定・ログ出力
|
||||
- `tools/stage1_minimal.sh`: 最小限の5変数で実行
|
||||
- エラー時に「どの環境変数が未設定か」を診断
|
||||
|
||||
3. **行番号マップ簡易版**(3日)
|
||||
- Stage-B側で`#line <num> "<file>"`コメント挿入
|
||||
- Rust側のパーサーエラーで元ファイル名を表示
|
||||
- 完全なsource mapは後回し(まず動く最小実装)
|
||||
|
||||
**成果物**:
|
||||
- 開発者が「何を設定すればいいか」明確化
|
||||
- エラー箇所の特定時間を50%削減
|
||||
- 後方互換性100%(既存コード無変更)
|
||||
|
||||
---
|
||||
|
||||
### C-2. 中期解決(Phase 25.3-25.5: 3-6ヶ月)
|
||||
|
||||
**目標**: アーキテクチャの根本整理
|
||||
|
||||
**タスク**:
|
||||
1. **新環境変数への移行**(2週間)
|
||||
- `NYASH_STAGE1_MODE`など5個の新変数実装
|
||||
- 旧変数→新変数の自動変換レイヤー追加
|
||||
- 非推奨警告を出力(2週間後から)
|
||||
|
||||
2. **CLI統一インターフェース**(1ヶ月)
|
||||
- `nyash stage1 <subcommand>`形式を実装
|
||||
- `clap`相当の引数パーサーを.hako側に実装
|
||||
- `--`以降の引数処理を標準化
|
||||
|
||||
3. **Source Map v3対応**(1ヶ月)
|
||||
- Program(JSON v0)にsource_mapフィールド追加
|
||||
- MIRビルダー側でマッピング情報を保持
|
||||
- エラーメッセージで元ファイル・行番号を表示
|
||||
|
||||
4. **設定ファイル統合**(2週間)
|
||||
- `nyash.toml`に`[stage1]`セクション追加
|
||||
- ランタイムポリシーを環境変数から移行
|
||||
- 優先度階層テスト(CLI > env > toml > default)
|
||||
|
||||
**成果物**:
|
||||
- 環境変数25個→5個に削減(80%削減)
|
||||
- 引数経路を1つに統一
|
||||
- デバッグ体験が劇的改善
|
||||
|
||||
---
|
||||
|
||||
### C-3. 長期解決(Phase 26+: 6ヶ月以降)
|
||||
|
||||
**目標**: 完全セルフホスティング達成
|
||||
|
||||
**タスク**:
|
||||
1. **Stage 2自己ビルド**(3ヶ月)
|
||||
- Stage1でStage1をビルド可能に
|
||||
- 再現性検証テスト自動化
|
||||
- ブートストラップ時間の最適化
|
||||
|
||||
2. **プリコンパイル済みプレリュード**(2ヶ月)
|
||||
- MIRバイナリフォーマット設計
|
||||
- プレリュード事前コンパイル機能
|
||||
- リンク機構実装
|
||||
|
||||
3. **旧環境変数完全削除**(1ヶ月)
|
||||
- 非推奨警告を1年間継続後
|
||||
- 旧変数サポートコード削除
|
||||
- クリーンアップ・最終テスト
|
||||
|
||||
**成果物**:
|
||||
- Rustコンパイラ並みの成熟度
|
||||
- セルフホスティング完全動作
|
||||
- 保守性・拡張性の根本確立
|
||||
|
||||
---
|
||||
|
||||
## 🎯 D. 最小限の環境変数セット(5個)
|
||||
|
||||
### D-1. 推奨セット(開発・本番両用)
|
||||
|
||||
```bash
|
||||
# 1. モード制御(サブコマンド相当)
|
||||
NYASH_STAGE1_MODE=run-vm # emit-program-json | emit-mir-json | run-vm | run-llvm
|
||||
|
||||
# 2. 入力ファイル(または "-" でSTDIN)
|
||||
NYASH_STAGE1_INPUT=source.hako
|
||||
|
||||
# 3. 機能トグル(カンマ区切り)
|
||||
NYASH_FEATURES=using,parser-stage3,plugins
|
||||
|
||||
# 4. デバッグ/ログは NYASH_CLI_VERBOSE / STAGE1_CLI_DEBUG を併用(暫定)
|
||||
# 5. 設定ファイルパスは現状なし(NYASH_CONFIG は未使用のため削除済み)
|
||||
```
|
||||
|
||||
### D-2. 設定ファイル形式(nyash.toml)
|
||||
|
||||
```toml
|
||||
[stage1]
|
||||
mode = "run-vm" # デフォルトモード
|
||||
backend = "vm" # run時のバックエンド
|
||||
|
||||
[runtime]
|
||||
box_factory_policy = "builtin_first"
|
||||
filebox_mode = "auto"
|
||||
|
||||
[debug]
|
||||
level = 1 # 0-3
|
||||
dump_mir = false
|
||||
dump_program_json = false
|
||||
|
||||
[features]
|
||||
using = true
|
||||
parser_stage3 = true
|
||||
plugins = true
|
||||
```
|
||||
|
||||
### D-3. 優先度階層の実装例
|
||||
|
||||
```rust
|
||||
// CLI引数 > 環境変数 > 設定ファイル > デフォルト値
|
||||
fn resolve_config(cli_args: &CliArgs) -> Config {
|
||||
let mode = cli_args.mode // 1. CLI引数(最優先)
|
||||
.or_else(|| std::env::var("NYASH_STAGE1_MODE").ok()) // 2. 環境変数
|
||||
.or_else(|| load_from_toml("stage1.mode")) // 3. 設定ファイル
|
||||
.unwrap_or("run-vm".to_string()); // 4. デフォルト値
|
||||
|
||||
Config {
|
||||
mode,
|
||||
debug_level: resolve_debug_level(cli_args),
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📈 E. 期待される効果
|
||||
|
||||
### E-1. 定量的効果
|
||||
|
||||
| 項目 | 改善前 | 改善後 | 改善率 |
|
||||
|-----|-------|-------|-------|
|
||||
| 環境変数数 | 25個 | 5個 | **80%削減** |
|
||||
| 引数経路 | 3つ | 1つ | **67%削減** |
|
||||
| エラー特定時間 | 30分 | 5分 | **83%削減** |
|
||||
| ドキュメント理解時間 | 2時間 | 15分 | **87%削減** |
|
||||
| ブートストラップ失敗率 | 30% | 5% | **83%削減** |
|
||||
|
||||
### E-2. 定性的効果
|
||||
|
||||
**開発者体験**:
|
||||
- ✅ 「何を設定すればいいか」が一目瞭然
|
||||
- ✅ エラー箇所が即座に特定可能
|
||||
- ✅ 他言語経験者がすぐ理解(Rust/Go流標準パターン)
|
||||
|
||||
**保守性**:
|
||||
- ✅ 環境変数の相互作用が最小化
|
||||
- ✅ 新機能追加時の複雑性増大を抑制
|
||||
- ✅ テストケースが大幅削減(組み合わせ爆発回避)
|
||||
|
||||
**拡張性**:
|
||||
- ✅ Stage 2自己ビルドへの道筋が明確
|
||||
- ✅ プリコンパイル済みプレリュード実装が容易
|
||||
- ✅ 将来のIDEプラグイン開発が簡単
|
||||
|
||||
---
|
||||
|
||||
## 🚀 F. 実装開始ガイド
|
||||
|
||||
### F-1. Phase 25.2タスク(今すぐ開始)
|
||||
|
||||
**Week 1: ドキュメント整備**
|
||||
```bash
|
||||
# 1. 環境変数リスト作成
|
||||
docs/reference/environment-variables.md
|
||||
- 現在の25個を分類(必須/推奨/非推奨/削除予定)
|
||||
- 相互作用図を追加(Mermaid図解)
|
||||
|
||||
# 2. クイックスタートガイド更新
|
||||
docs/guides/selfhosting-quickstart.md
|
||||
- 最小5変数での起動例
|
||||
- トラブルシューティングチェックリスト
|
||||
```
|
||||
|
||||
**Week 2: ヘルパースクリプト**
|
||||
```bash
|
||||
# 1. デバッグヘルパー実装
|
||||
tools/stage1_debug.sh
|
||||
- 環境変数を自動設定・ログ出力
|
||||
- 未設定変数の診断機能
|
||||
|
||||
# 2. 最小実行スクリプト
|
||||
tools/stage1_minimal.sh
|
||||
- 5変数のみで実行
|
||||
- 成功時のテンプレートとして提供
|
||||
```
|
||||
|
||||
実装メモ(2025-11 時点の足場)
|
||||
- `tools/stage1_debug.sh` と `tools/stage1_minimal.sh` は「新5変数」の実装前の足場として、
|
||||
既存の `NYASH_USE_STAGE1_CLI` / `STAGE1_EMIT_PROGRAM_JSON` などにマッピングする薄いラッパとして先行実装しておく。
|
||||
- これにより:
|
||||
- 開発者は「まずこの2スクリプト経由で」 Stage‑1 経路を叩けばよくなる。
|
||||
- 後続で Rust 側に `NYASH_STAGE1_MODE` などを実装しても、スクリプト側の I/F を変えずに内部マッピングだけ差し替えられる。
|
||||
- CI やドキュメントも「スクリプト経由」の説明に統一できる。
|
||||
|
||||
**Week 3-4: 行番号マップ簡易版**
|
||||
```rust
|
||||
// src/runner/stage1_bridge.rs
|
||||
impl Stage1Bridge {
|
||||
fn inject_line_markers(source: &str, filename: &str) -> String {
|
||||
// #line <num> "<file>" コメント挿入
|
||||
}
|
||||
|
||||
fn parse_error_with_source_map(error: &str) -> String {
|
||||
// エラーメッセージから元ファイル・行番号を復元
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### F-2. Phase 25.3-25.5タスク(中期実装)
|
||||
|
||||
**Month 1: 新環境変数への移行**
|
||||
- `NYASH_STAGE1_MODE`など5変数の実装
|
||||
- 旧変数→新変数の互換レイヤー
|
||||
- 非推奨警告の実装
|
||||
|
||||
**Month 2: CLI統一インターフェース**
|
||||
- `nyash stage1 <subcommand>`形式
|
||||
- 引数パーサーの実装(.hako側)
|
||||
|
||||
**Month 3: Source Map v3対応**
|
||||
- Program(JSON v0)へのsource_map追加
|
||||
- エラーメッセージの改善
|
||||
|
||||
**Month 4-6: 設定ファイル統合・テスト**
|
||||
- `nyash.toml`への移行
|
||||
- 優先度階層の完全テスト
|
||||
|
||||
---
|
||||
|
||||
## 📚 G. 参考資料
|
||||
|
||||
### G-1. 業界標準ドキュメント
|
||||
|
||||
- **Rust Compiler Development Guide**: https://rustc-dev-guide.rust-lang.org/building/bootstrapping/
|
||||
- **Go Command Documentation**: https://go.dev/doc/install/source
|
||||
- **POSIX Utility Conventions**: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html
|
||||
- **Source Map v3 Spec**: https://sourcemaps.info/spec.html
|
||||
|
||||
### G-2. 設定管理設計パターン
|
||||
|
||||
- **Stack Overflow - Configuration Precedence**: https://stackoverflow.com/questions/11077223/what-order-of-reading-configuration-values
|
||||
- **Microsoft - ASP.NET Core Configuration**: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/
|
||||
- **AWS CLI Environment Variables**: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html
|
||||
|
||||
### G-3. Nyash内部ドキュメント
|
||||
|
||||
- `CURRENT_TASK.md`: Phase 25.1-25.2の進捗状況
|
||||
- `docs/private/roadmap2/phases/phase-25.1/stage1-usingresolver-loopform.md`: Stage1設計詳細
|
||||
- `docs/development/runtime/cli-hakorune-stage1.md`: CLI仕様(SSOT)
|
||||
- `src/runner/stage1_bridge.rs`: Rust側ブリッジ実装
|
||||
- `lang/src/runner/stage1_cli.hako`: Stage1 CLI本体
|
||||
|
||||
---
|
||||
|
||||
## ✅ H. チェックリスト
|
||||
|
||||
### H-1. 短期実装(Phase 25.2)
|
||||
|
||||
- [ ] 環境変数ドキュメント作成(`docs/reference/environment-variables.md`)
|
||||
- [ ] デバッグヘルパースクリプト実装(`tools/stage1_debug.sh`)
|
||||
- [ ] 最小実行スクリプト実装(`tools/stage1_minimal.sh`)
|
||||
- [ ] 行番号マップ簡易版実装(`#line`コメント挿入)
|
||||
- [ ] エラーメッセージ改善(元ファイル名・行番号表示)
|
||||
|
||||
### H-2. 中期実装(Phase 25.3-25.5)
|
||||
|
||||
- [ ] 新環境変数5個の実装
|
||||
- [ ] 旧変数→新変数の互換レイヤー
|
||||
- [ ] 非推奨警告の実装
|
||||
- [ ] `nyash stage1 <subcommand>` CLI実装
|
||||
- [ ] Source Map v3対応
|
||||
- [ ] `nyash.toml`への設定移行
|
||||
- [ ] 優先度階層の完全テスト
|
||||
|
||||
### H-3. 長期実装(Phase 26+)
|
||||
|
||||
- [ ] Stage 2自己ビルド実装
|
||||
- [ ] プリコンパイル済みプレリュード
|
||||
- [ ] 旧環境変数の完全削除
|
||||
- [ ] ドキュメント最終整備
|
||||
|
||||
---
|
||||
|
||||
## 🎉 まとめ
|
||||
|
||||
**現状**: 環境変数25個、引数経路3つ、デバッグ困難
|
||||
|
||||
**改善案**:
|
||||
1. **環境変数を5個に削減**(階層化・統合)
|
||||
2. **CLI引数を1経路に統一**(Git/Cargo流サブコマンド)
|
||||
3. **Source Map対応**(エラー箇所即座特定)
|
||||
4. **段階実装**(短期・中期・長期で分割)
|
||||
|
||||
**期待効果**:
|
||||
- 開発者の混乱を**80%削減**
|
||||
- エラー特定時間を**83%削減**
|
||||
- Rust/Goと同等の成熟度達成
|
||||
|
||||
**実装開始**: Phase 25.2から段階的にスタート、後方互換性100%維持
|
||||
|
||||
---
|
||||
|
||||
**Document Version**: 1.0
|
||||
**Date**: 2025-11-21
|
||||
**Author**: Claude (Anthropic Claude Sonnet 4.5)
|
||||
**Status**: Proposal - Ready for Review
|
||||
@ -1,137 +0,0 @@
|
||||
# Property System Revolution for Nyash (2025-09-18 Breakthrough)
|
||||
|
||||
Status: **BREAKTHROUGH COMPLETED** - Final syntax decided through AI collaboration with ChatGPT, Claude, and Codex.
|
||||
|
||||
## 🌟 Revolutionary Achievement
|
||||
Today we achieved the **Property System Revolution** - a complete unification of stored fields, computed properties, lazy evaluation, and birth-time initialization into a single, elegant syntax system through AI collaboration with ChatGPT5, Claude, and Codex.
|
||||
|
||||
## 🎯 Final Property System Design
|
||||
|
||||
### The Four-Category Breakthrough
|
||||
After dialectical discussion with multiple AI agents, we reached the perfect synthesis:
|
||||
|
||||
#### 1. **stored** - Traditional Field Storage
|
||||
```nyash
|
||||
box Example {
|
||||
name: StringBox // Default initialization
|
||||
count: IntegerBox = 0 // Explicit initialization
|
||||
}
|
||||
```
|
||||
- **Semantics**: O(1) slot read/write, assignment allowed
|
||||
- **Use Case**: Traditional object fields, counters, configurations
|
||||
|
||||
#### 2. **computed** - Calculated Every Access
|
||||
```nyash
|
||||
box Example {
|
||||
size: IntegerBox { me.items.count() }
|
||||
full_name: StringBox { me.first + " " + me.last }
|
||||
}
|
||||
```
|
||||
- **Semantics**: Evaluate body on each read, assignment error unless setter declared
|
||||
- **Use Case**: Derived values, dynamic calculations, Python @property equivalent
|
||||
|
||||
#### 3. **once** - Lazy Evaluation with Caching
|
||||
```nyash
|
||||
box Example {
|
||||
once expensive_data: DataBox { heavy_computation() }
|
||||
once config: ConfigBox { loadConfiguration() }
|
||||
}
|
||||
```
|
||||
- **Semantics**: Evaluate on first read, cache result, return cached value thereafter
|
||||
- **Use Case**: Heavy computations, file loading, Python @cached_property equivalent
|
||||
- **Exception Handling**: Poison-on-throw strategy for safety
|
||||
|
||||
#### 4. **birth_once** - Eager Evaluation at Object Creation
|
||||
```nyash
|
||||
box Example {
|
||||
birth_once startup_data: DataBox { initialize_system() }
|
||||
|
||||
birth() {
|
||||
// birth_once properties already initialized!
|
||||
me.ready = true
|
||||
}
|
||||
}
|
||||
```
|
||||
- **Semantics**: Evaluated before user birth() in declaration order
|
||||
- **Use Case**: System initialization, dependency setup, startup-critical data
|
||||
|
||||
## 🌟 Revolutionary Python Integration
|
||||
|
||||
### Perfect Mapping Strategy
|
||||
```python
|
||||
# Python side
|
||||
class DataProcessor:
|
||||
def __init__(self):
|
||||
self.value = 42 # → stored
|
||||
|
||||
@property
|
||||
def computed_result(self): # → computed
|
||||
return self.value * 2
|
||||
|
||||
@functools.cached_property
|
||||
def expensive_data(self): # → once
|
||||
return heavy_computation()
|
||||
```
|
||||
|
||||
```nyash
|
||||
// Auto-generated Nyash (revolutionary 1:1 mapping!)
|
||||
box DataProcessor {
|
||||
value: IntegerBox // stored
|
||||
computed_result: IntegerBox { me.value * 2 } // computed
|
||||
once expensive_data: ResultBox { heavy_computation() } // once
|
||||
|
||||
birth() {
|
||||
me.value = 42
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Performance Revolution
|
||||
- **computed properties**: No caching overhead, pure calculation
|
||||
- **once properties**: 10-50x faster than Python cached_property (LLVM optimization)
|
||||
- **birth_once properties**: Startup optimization, dependency injection pattern
|
||||
- **Overall**: Python code → 5-20x faster native binary
|
||||
|
||||
Handlers (Stage‑3)
|
||||
- Postfix `catch/cleanup` are allowed for computed/once/birth_once/method blocks.
|
||||
- Stored does not accept handlers.
|
||||
|
||||
Semantics
|
||||
- stored: O(1) slot read; `= expr` evaluated once during construction; assignment allowed.
|
||||
- computed: evaluate on each read; assignment is an error unless a setter is declared.
|
||||
- once: evaluate on first read, cache the result, and return it thereafter. If the first evaluation throws and there is no `catch`, mark poisoned and rethrow the same error on later reads (no retry).
|
||||
- birth_once: evaluated before user `birth` body in declaration order; uncaught error aborts construction. Cycles are rejected.
|
||||
|
||||
Lowering (no JSON v0 change)
|
||||
- stored → slot
|
||||
- computed → synthesize `__get_name():T { try body; catch; finally }`, resolve reads to call
|
||||
- once → add hidden `__name: Option<T>` and first-read initialization in `__get_name()`; poison on uncaught error
|
||||
- birth_once → hidden `__name: T` initialized before user `birth` body in declaration order; handler blocks apply per initializer
|
||||
- method → unchanged; postfix handlers lower to try/catch/finally
|
||||
|
||||
EBNF (delta)
|
||||
```
|
||||
box_decl := 'box' IDENT '{' member* '}'
|
||||
member := stored | computed | once_decl | birth_once_decl | method_decl
|
||||
stored := IDENT ':' TYPE ( '=' expr )?
|
||||
computed := IDENT ':' TYPE block handler_tail?
|
||||
once_decl := 'once' IDENT ':' TYPE block handler_tail?
|
||||
birth_once_decl:= 'birth_once' IDENT ':' TYPE block handler_tail?
|
||||
method_decl := IDENT '(' params? ')' ( ':' TYPE )? block handler_tail?
|
||||
handler_tail := ( catch_block )? ( cleanup_block )?
|
||||
catch_block := 'catch' ( '(' ( IDENT IDENT | IDENT )? ')' )? block
|
||||
cleanup_block := 'cleanup' block
|
||||
```
|
||||
|
||||
Diagnostics
|
||||
- Assignment to computed/once/birth_once: error with fix-it (“define a setter or use stored property”).
|
||||
- Once poison: first read throws → remember error; subsequent reads rethrow immediately.
|
||||
- Birth order: evaluated before user `birth`, in declaration order; cycle detection emits a clear error with the chain.
|
||||
|
||||
Flags
|
||||
- Parser gate: `NYASH_ENABLE_UNIFIED_MEMBERS=1`
|
||||
- Stage‑3 for handlers: `NYASH_PARSER_STAGE3=1`
|
||||
|
||||
Notes
|
||||
- User experience: read is uniform (`obj.name`), write differs by kind; this keeps mental model simple.
|
||||
- Future: setter syntax (`name: T { get {…} set(v) {…} }`) and aliases (`slot/calc/lazy`) can be added without breaking this core.
|
||||
@ -1,306 +0,0 @@
|
||||
# 🚨 緊急修正 Issue: Everything is Box設計でのclone_box()問題根本解決
|
||||
|
||||
## 📋 Issue概要
|
||||
**優先度**: 🔴 **URGENT** - 全ステートフルBox(SocketBox, P2PBox等)に影響
|
||||
**期間**: 2-3日
|
||||
**担当**: Copilot様
|
||||
|
||||
## 🎯 問題の核心
|
||||
|
||||
**ユーザー指摘**: 「いや 単純に rustの使い方 へたなだけじゃーーい!」
|
||||
**Gemini先生確認**: Everything is Box設計は正しい。問題は `clone_box()` を使うべきでない場所で使っていること
|
||||
|
||||
### 🚨 真犯人特定済み(3箇所)
|
||||
|
||||
1. **`src/interpreter/core.rs:366`** - `resolve_variable()`
|
||||
2. **`src/instance.rs:275`** - `get_field()`
|
||||
3. **`src/interpreter/expressions.rs:779`** - `execute_field_access()`
|
||||
|
||||
### 💥 現在の症状
|
||||
```nyash
|
||||
me.server.bind("127.0.0.1", 8080) // ✅ SocketBox ID=10, is_server=true
|
||||
me.server.isServer() // ❌ SocketBox ID=19, is_server=false (別インスタンス!)
|
||||
```
|
||||
|
||||
## 🛠️ 解決策:Arc<dyn NyashBox>への段階的移行
|
||||
|
||||
**Gemini先生推奨**: `Box<dyn NyashBox>` → `Arc<dyn NyashBox>` で参照共有実現
|
||||
|
||||
---
|
||||
|
||||
## 📋 段階的修正手順(Copilot実装ガイド)
|
||||
|
||||
### **Phase 1: 型エイリアス導入**
|
||||
|
||||
#### 1.1 `src/box_trait.rs`に型エイリアス追加
|
||||
```rust
|
||||
// ファイル先頭のuse文の後に追加
|
||||
use std::sync::Arc;
|
||||
|
||||
// 新しい型エイリアス - 将来的にBox<dyn NyashBox>を全て置き換える
|
||||
pub type SharedNyashBox = Arc<dyn NyashBox>;
|
||||
```
|
||||
|
||||
#### 1.2 NyashBoxトレイトに新メソッド追加
|
||||
```rust
|
||||
// src/box_trait.rs のNyashBoxトレイト内に追加
|
||||
pub trait NyashBox: BoxCore + Debug {
|
||||
// 既存メソッド...
|
||||
|
||||
/// Arc参照を返す新しいcloneメソッド(参照共有)
|
||||
fn clone_arc(&self) -> SharedNyashBox {
|
||||
Arc::new(self.clone())
|
||||
}
|
||||
|
||||
/// 従来のclone_box(互換性維持のため残す)
|
||||
fn clone_box(&self) -> Box<dyn NyashBox>;
|
||||
}
|
||||
```
|
||||
|
||||
### **Phase 2: データ構造変更**
|
||||
|
||||
#### 2.1 `src/instance.rs` - InstanceBox修正
|
||||
```rust
|
||||
// InstanceBox構造体のfields型変更
|
||||
pub struct InstanceBox {
|
||||
pub base: BoxBase,
|
||||
pub class_name: String,
|
||||
pub fields: Arc<Mutex<HashMap<String, SharedNyashBox>>>, // ← Box→Arc
|
||||
// 他フィールドはそのまま
|
||||
}
|
||||
|
||||
// コンストラクタ修正
|
||||
impl InstanceBox {
|
||||
pub fn new(class_name: String, fields: Vec<String>) -> Self {
|
||||
let mut field_map: HashMap<String, SharedNyashBox> = HashMap::new();
|
||||
for field in fields {
|
||||
field_map.insert(field, Arc::new(VoidBox::new())); // Box::new → Arc::new
|
||||
}
|
||||
|
||||
InstanceBox {
|
||||
base: BoxBase::new(),
|
||||
class_name,
|
||||
fields: Arc::new(Mutex::new(field_map)),
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2 `src/interpreter/core.rs` - NyashInterpreter修正
|
||||
```rust
|
||||
// NyashInterpreter構造体の変数管理型変更
|
||||
pub struct NyashInterpreter {
|
||||
// 既存フィールド...
|
||||
pub local_vars: HashMap<String, SharedNyashBox>, // ← Box→Arc
|
||||
pub outbox_vars: HashMap<String, SharedNyashBox>, // ← Box→Arc
|
||||
// 他フィールドはそのまま
|
||||
}
|
||||
```
|
||||
|
||||
### **Phase 3: 問題箇所修正(真犯人退治)**
|
||||
|
||||
#### 3.1 `src/interpreter/core.rs:366` - resolve_variable修正
|
||||
```rust
|
||||
// 修正前:
|
||||
let cloned_value = local_value.clone_box(); // ← 新インスタンス作成(問題)
|
||||
return Ok(cloned_value);
|
||||
|
||||
// 修正後:
|
||||
pub(super) fn resolve_variable(&self, name: &str) -> Result<SharedNyashBox, RuntimeError> {
|
||||
// ... 既存のログ処理
|
||||
|
||||
// 2. local変数をチェック
|
||||
if let Some(local_value) = self.local_vars.get(name) {
|
||||
eprintln!("🔍 DEBUG: Found '{}' in local_vars", name);
|
||||
|
||||
// 🔧 修正:clone_box() → Arc::clone() で参照共有
|
||||
let shared_value = Arc::clone(local_value);
|
||||
|
||||
core_deep_debug_log(&format!("✅ RESOLVE_VARIABLE shared reference: {} id={}",
|
||||
name, shared_value.box_id()));
|
||||
|
||||
return Ok(shared_value);
|
||||
}
|
||||
|
||||
// 残りの処理も同様にSharedNyashBoxを返すよう修正
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.2 `src/instance.rs:275` - get_field修正
|
||||
```rust
|
||||
// 修正前:
|
||||
pub fn get_field(&self, field_name: &str) -> Option<Box<dyn NyashBox>> {
|
||||
self.fields.lock().unwrap().get(field_name).map(|v| v.clone_box()) // ← 複製(問題)
|
||||
}
|
||||
|
||||
// 修正後:
|
||||
pub fn get_field(&self, field_name: &str) -> Option<SharedNyashBox> {
|
||||
eprintln!("✅ FIX: get_field('{}') returning shared Arc reference", field_name);
|
||||
|
||||
// 🔧 修正:v.clone_box() → Arc::clone(v) で参照共有
|
||||
self.fields.lock().unwrap().get(field_name).map(Arc::clone)
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.3 `src/interpreter/expressions.rs:779` - execute_field_access修正
|
||||
```rust
|
||||
// 修正前:
|
||||
let field_value = instance.get_field(field) // get_fieldがBoxを返していた
|
||||
|
||||
// 修正後:
|
||||
fn execute_field_access(&mut self, object: &ASTNode, field: &str)
|
||||
-> Result<SharedNyashBox, RuntimeError> { // ← 戻り値型変更
|
||||
|
||||
// オブジェクト評価
|
||||
let obj_value = self.execute_expression(object)?;
|
||||
|
||||
if let Some(instance) = obj_value.as_any().downcast_ref::<InstanceBox>() {
|
||||
// フィールドアクセス - get_fieldがArc参照を返すように修正済み
|
||||
let field_value = instance.get_field(field)
|
||||
.ok_or_else(|| RuntimeError::InvalidOperation {
|
||||
message: format!("Field '{}' not found in {}", field, instance.class_name),
|
||||
})?;
|
||||
|
||||
eprintln!("✅ FIELD ACCESS: Returning shared reference id={}", field_value.box_id());
|
||||
|
||||
Ok(field_value) // Arc参照を返す
|
||||
} else {
|
||||
// エラー処理...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **Phase 4: set_field修正**
|
||||
|
||||
#### 4.1 `src/instance.rs` - set_field修正
|
||||
```rust
|
||||
// set_fieldも引数の型をSharedNyashBoxに変更
|
||||
pub fn set_field(&self, field_name: &str, value: SharedNyashBox) -> Result<(), String> {
|
||||
eprintln!("🔧 INSTANCE: set_field('{}') with shared Arc reference id={}",
|
||||
field_name, value.box_id());
|
||||
|
||||
let mut fields = self.fields.lock().unwrap();
|
||||
if fields.contains_key(field_name) {
|
||||
if let Some(old_value) = fields.get(field_name) {
|
||||
eprintln!("🔧 INSTANCE: Replacing field '{}': old_id={} -> new_id={}",
|
||||
field_name, old_value.box_id(), value.box_id());
|
||||
}
|
||||
fields.insert(field_name.to_string(), value);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("Field '{}' does not exist in {}", field_name, self.class_name))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 テスト方法
|
||||
|
||||
### テストファイル作成
|
||||
```bash
|
||||
# テスト用Nyashコード
|
||||
echo 'static box Main {
|
||||
init { server }
|
||||
|
||||
main() {
|
||||
me.server = new SocketBox()
|
||||
|
||||
print("=== Before bind ===")
|
||||
print("isServer: " + me.server.isServer())
|
||||
|
||||
me.server.bind("127.0.0.1", 8080)
|
||||
|
||||
print("=== After bind ===")
|
||||
print("isServer: " + me.server.isServer()) // これがtrueになれば修正成功!
|
||||
|
||||
return me.server.isServer()
|
||||
}
|
||||
}' > test_arc_fix.hako
|
||||
```
|
||||
|
||||
### 実行・検証
|
||||
```bash
|
||||
# ビルド・実行
|
||||
cargo build --release
|
||||
./target/release/nyash test_arc_fix.hako
|
||||
|
||||
# 期待される結果:
|
||||
# === Before bind ===
|
||||
# isServer: false
|
||||
# === After bind ===
|
||||
# isServer: true ← これが true になれば成功!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 修正対象ファイル一覧
|
||||
|
||||
### 必須修正ファイル
|
||||
1. **`src/box_trait.rs`** - 型エイリアス・clone_arcメソッド追加
|
||||
2. **`src/instance.rs`** - InstanceBox構造体・get_field・set_field修正
|
||||
3. **`src/interpreter/core.rs`** - NyashInterpreter・resolve_variable修正
|
||||
4. **`src/interpreter/expressions.rs`** - execute_field_access修正
|
||||
|
||||
### 追加修正が必要になる可能性があるファイル
|
||||
- `src/interpreter/statements.rs` - 代入処理
|
||||
- `src/interpreter/objects.rs` - オブジェクト生成処理
|
||||
- その他 `Box<dyn NyashBox>` を使用している箇所
|
||||
|
||||
## 🎯 修正完了条件
|
||||
|
||||
### ✅ 成功条件
|
||||
1. **テスト成功**: `test_arc_fix.hako` で `isServer: true` が表示される
|
||||
2. **コンパイル成功**: `cargo build --release` でエラーなし
|
||||
3. **既存テスト成功**: `cargo test` でテスト通過
|
||||
4. **デバッグログ確認**: 同一SocketBox IDが維持される
|
||||
|
||||
### 🔍 確認ポイント
|
||||
- SocketBoxログで同じIDが表示される(ID変化なし)
|
||||
- 状態が正しく保持される(bind後にisServer=true)
|
||||
- メモリリークが発生しない(Arc参照カウント正常)
|
||||
|
||||
---
|
||||
|
||||
## 💡 実装のコツ(Copilot向け)
|
||||
|
||||
### 段階的実装推奨
|
||||
1. **まず型エイリアス追加** → コンパイルエラー確認
|
||||
2. **データ構造を段階的に変更** → 各ファイル別に修正
|
||||
3. **最後に問題の3箇所修正** → 動作テスト実行
|
||||
|
||||
### よくあるコンパイルエラー対処
|
||||
- **型不一致**: `Box<dyn NyashBox>` と `SharedNyashBox` の混在
|
||||
→ 段階的に `SharedNyashBox` に統一
|
||||
- **ライフタイム問題**: Arc使用により大部分が解決
|
||||
- **メソッドシグネチャ不一致**: 戻り値型を `SharedNyashBox` に変更
|
||||
|
||||
### デバッグのポイント
|
||||
- 修正前後でSocketBox IDが同じになることを確認
|
||||
- `Arc::strong_count()` で参照数確認(デバッグ用)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 期待される効果
|
||||
|
||||
### 🎉 修正後の動作
|
||||
```nyash
|
||||
me.server.bind("127.0.0.1", 8080) // ✅ SocketBox ID=10, is_server=true
|
||||
me.server.isServer() // ✅ SocketBox ID=10, is_server=true (同じインスタンス!)
|
||||
```
|
||||
|
||||
### 📈 影響範囲
|
||||
- **全ステートフルBox**: SocketBox, P2PBox, HTTPServerBox等が正常動作
|
||||
- **全フィールドアクセス**: `obj.field` で状態保持
|
||||
- **全変数アクセス**: `me`変数で状態保持
|
||||
- **性能向上**: 不要なclone処理削減
|
||||
|
||||
### 🏆 Everything is Box設計完成
|
||||
ユーザー指摘通り、設計は正しく、**Rustの所有権システムを正しく使う**ことで、真の「Everything is Box」が実現されます!
|
||||
|
||||
---
|
||||
|
||||
**実装担当**: Copilot様
|
||||
**レビュー**: Claude & User
|
||||
**完了目標**: 2-3日以内
|
||||
Reference in New Issue
Block a user