docs: Add Phase 9.75f Option C implementation plans

- Phase 9.75f-1: FileBox dynamic library (immediate)
- Phase 9.75f-2: Math/Time boxes dynamic (this week)
- Phase 9.75f-3: Core types experiment (future)
- Update CURRENT_TASK.md with Option C strategy
- Refine todo list for phased implementation
This commit is contained in:
Moe Charm
2025-08-17 04:06:42 +09:00
parent 1493ad7e94
commit 349dba24b5
4 changed files with 599 additions and 12 deletions

View File

@ -364,26 +364,39 @@ if let TokenType::IDENTIFIER(id) = &self.current_token().token_type {
**現在状況**: 🚀 **Phase 9.75f ビルトインBox動的ライブラリ分離開始**
**最終更新**: 2025-08-17 03:30
## 🔥 **Phase 9.75f: 緊急ビルド時間改善**
## 🔥 **Phase 9.75f: 緊急ビルド時間改善Option C段階的実装**
### 🎯 **動的ライブラリ化によるビルド革命**
- **現状**: 16個のビルトインBox静的リンク → 2分以上のビルド
- **目標**: コア2MB + 動的ライブラリ → 15秒ビルド
### 📋 **Gemini先生の推奨実装**
1. **C ABI + libloading**: 最も安定した方法
2. **段階的移行**: インタープリターExternCall → プラグイン化
3. **メモリ管理**: ハンドルパターンでArc<RwLock>問題解決
### 📋 **Option C: 段階的移行戦略**
1. **[9.75f-1]**: FileBox動的化即実装
- 詳細: [phase_9_75f_1_filebox_dynamic.md](docs/予定/native-plan/issues/phase_9_75f_1_filebox_dynamic.md)
- libnyash_file.so作成、C ABI実装
- 目標: 15秒のビルド時間短縮
2. **[9.75f-2]**: Math/Time系動的化今週中
- 詳細: [phase_9_75f_2_math_time_dynamic.md](docs/予定/native-plan/issues/phase_9_75f_2_math_time_dynamic.md)
- 統合プラグインMath, Random, Time
- 目標: さらに30秒短縮
3. **[9.75f-3]**: 基本型実験(将来)
- 詳細: [phase_9_75f_3_core_types_experiment.md](docs/予定/native-plan/issues/phase_9_75f_3_core_types_experiment.md)
- --dynamic-all フラグで完全動的化
- 目標: 5秒ビルド実験的
### ✅ **完了タスク**
- FFI-ABI file実装stdlib方式
- MIRビルダーfile.read/write追加
- Gemini先生への相談・回答取得
- FFI-ABI file実装テスト(削除済み
- Gemini先生への相談・アドバイス取得
- FileBox実装確認存在・利用可能
- Option C実装計画策定
### 🚀 **次のステップ**
1. インタープリターでExternCall直接実行
2. FileBoxの元実装を探して置き換え
3. プラグインアーキテクチャ基盤構築
### 🚀 **現在の作業: 9.75f-1 FileBox動的化**
1. workspace構成準備
2. FileBoxプラグイン作成
3. C ABI関数実装
4. インタープリター統合
## 🌐 **WASM研究メモ**

View File

@ -0,0 +1,175 @@
# Phase 9.75f-1: FileBox動的ライブラリ化第一段階
## 🎯 目的
- FileBoxを最初の動的ライブラリ化対象として実装
- ビルド時間短縮効果の実証(目標: 15秒短縮
- 動的ライブラリアーキテクチャの検証
## 📋 実装計画
### Step 1: プロジェクト構造準備
```toml
# Cargo.toml (workspace)
[workspace]
members = [
"nyash-core",
"plugins/nyash-file",
]
# nyash-core/Cargo.toml
[dependencies]
libloading = "0.8"
[features]
default = ["static-boxes"]
static-boxes = []
dynamic-file = []
```
### Step 2: FileBox切り離し
```rust
// plugins/nyash-file/src/lib.rs
#[repr(C)]
pub struct FileBoxPlugin {
magic: u32, // 0x4E594153 ('NYAS')
version: u32,
api_version: u32,
}
#[no_mangle]
extern "C" fn nyash_plugin_init() -> *const FileBoxPlugin {
Box::into_raw(Box::new(FileBoxPlugin {
magic: 0x4E594153,
version: 1,
api_version: 1,
}))
}
// FileBox methods as C ABI functions
#[no_mangle]
extern "C" fn nyash_file_open(path: *const c_char) -> *mut c_void {
// FileBox::open implementation
}
#[no_mangle]
extern "C" fn nyash_file_read(handle: *mut c_void) -> *mut c_char {
// FileBox::read implementation
}
#[no_mangle]
extern "C" fn nyash_file_write(handle: *mut c_void, content: *const c_char) -> i32 {
// FileBox::write implementation
}
#[no_mangle]
extern "C" fn nyash_file_free(handle: *mut c_void) {
// Cleanup
}
```
### Step 3: インタープリター統合
```rust
// src/interpreter/plugin_loader.rs
use libloading::{Library, Symbol};
use std::sync::RwLock;
use std::collections::HashMap;
lazy_static! {
static ref PLUGIN_CACHE: RwLock<HashMap<String, Library>> =
RwLock::new(HashMap::new());
}
impl NyashInterpreter {
fn load_file_plugin(&mut self) -> Result<(), RuntimeError> {
#[cfg(feature = "dynamic-file")]
{
let mut cache = PLUGIN_CACHE.write().unwrap();
if !cache.contains_key("file") {
let lib_path = if cfg!(windows) {
"./plugins/nyash_file.dll"
} else if cfg!(target_os = "macos") {
"./plugins/libnyash_file.dylib"
} else {
"./plugins/libnyash_file.so"
};
unsafe {
let lib = Library::new(lib_path)?;
cache.insert("file".to_string(), lib);
}
}
}
Ok(())
}
}
```
### Step 4: execute_new修正
```rust
// src/interpreter/objects.rs
"FileBox" => {
#[cfg(feature = "static-boxes")]
{
// 既存の静的実装
let file_box = FileBox::open(&path)?;
Ok(Box::new(file_box))
}
#[cfg(feature = "dynamic-file")]
{
// 動的ライブラリ経由
self.load_file_plugin()?;
let cache = PLUGIN_CACHE.read().unwrap();
let lib = cache.get("file").unwrap();
unsafe {
let open_fn: Symbol<unsafe extern "C" fn(*const c_char) -> *mut c_void> =
lib.get(b"nyash_file_open")?;
let handle = open_fn(CString::new(path)?.as_ptr());
// FileBoxProxyでラップ
Ok(Box::new(FileBoxProxy { handle }))
}
}
}
```
### Step 5: FileBoxProxy実装
```rust
// src/interpreter/proxy_boxes.rs
struct FileBoxProxy {
handle: *mut c_void,
}
impl NyashBox for FileBoxProxy {
fn type_name(&self) -> &'static str {
"FileBox"
}
// メソッド呼び出しは動的ライブラリへ委譲
}
impl Drop for FileBoxProxy {
fn drop(&mut self) {
// nyash_file_free呼び出し
}
}
```
## 🎯 成功条件
1.`new FileBox(path)` が動的ライブラリ経由で動作
2. ✅ FileBoxのメソッドread, write, existsが正常動作
3. ✅ ビルド時間が15秒以上短縮
4. ✅ 静的/動的をfeature flagで切り替え可能
5. ✅ メモリリークなしvalgrindで確認
## ⚠️ 注意事項
- Windows/Mac/Linuxでのパス解決
- エラーハンドリング(プラグイン読み込み失敗時)
- ABI互換性C ABIで安定化
## 📊 測定項目
- ビルド時間(クリーンビルド)
- 起動時間(プラグインロード込み)
- FileBox操作のベンチマーク
- バイナリサイズ削減量

View File

@ -0,0 +1,200 @@
# Phase 9.75f-2: Math/Time系Box動的ライブラリ化第二段階
## 🎯 目的
- FileBox成功を受けて、Math/Random/Time系を動的化
- 複数Boxの単一ライブラリ化パターン検証
- ビルド時間追加短縮(目標: さらに30秒短縮
## 📋 実装計画
### Step 1: プラグイン構成
```toml
# plugins/nyash-math/Cargo.toml
[package]
name = "nyash-math"
crate-type = ["cdylib"]
[dependencies]
rand = "0.8"
chrono = "0.4"
```
### Step 2: 統合プラグインAPI
```rust
// plugins/nyash-math/src/lib.rs
#[repr(C)]
pub struct MathPlugin {
magic: u32,
version: u32,
// 複数Box型を1つのプラグインで提供
box_types: *const BoxTypeInfo,
box_count: usize,
}
#[repr(C)]
pub struct BoxTypeInfo {
name: *const c_char, // "MathBox", "RandomBox", etc.
constructor: extern "C" fn() -> *mut c_void,
methods: *const MethodInfo,
method_count: usize,
}
#[repr(C)]
pub struct MethodInfo {
name: *const c_char,
func: extern "C" fn(*mut c_void, *const c_void) -> *mut c_void,
}
// プラグイン初期化
#[no_mangle]
extern "C" fn nyash_plugin_init() -> *const MathPlugin {
static BOX_TYPES: &[BoxTypeInfo] = &[
BoxTypeInfo {
name: c"MathBox",
constructor: math_box_new,
methods: &MATH_METHODS,
method_count: MATH_METHODS.len(),
},
BoxTypeInfo {
name: c"RandomBox",
constructor: random_box_new,
methods: &RANDOM_METHODS,
method_count: RANDOM_METHODS.len(),
},
BoxTypeInfo {
name: c"TimeBox",
constructor: time_box_new,
methods: &TIME_METHODS,
method_count: TIME_METHODS.len(),
},
];
Box::into_raw(Box::new(MathPlugin {
magic: 0x4E594153,
version: 1,
box_types: BOX_TYPES.as_ptr(),
box_count: BOX_TYPES.len(),
}))
}
```
### Step 3: メソッド実装
```rust
// MathBox methods
static MATH_METHODS: &[MethodInfo] = &[
MethodInfo { name: c"sin", func: math_sin },
MethodInfo { name: c"cos", func: math_cos },
MethodInfo { name: c"sqrt", func: math_sqrt },
MethodInfo { name: c"pow", func: math_pow },
];
extern "C" fn math_sin(_self: *mut c_void, args: *const c_void) -> *mut c_void {
// 引数をFloatBoxとして解釈
// sin計算
// 結果をFloatBoxとして返す
}
// RandomBox methods
static RANDOM_METHODS: &[MethodInfo] = &[
MethodInfo { name: c"int", func: random_int },
MethodInfo { name: c"float", func: random_float },
MethodInfo { name: c"choice", func: random_choice },
];
// TimeBox methods
static TIME_METHODS: &[MethodInfo] = &[
MethodInfo { name: c"now", func: time_now },
MethodInfo { name: c"format", func: time_format },
MethodInfo { name: c"add", func: time_add },
];
```
### Step 4: 改良されたプラグインローダー
```rust
// src/interpreter/plugin_loader.rs
pub struct PluginRegistry {
plugins: HashMap<String, LoadedPlugin>,
box_registry: HashMap<String, BoxTypeEntry>,
}
struct LoadedPlugin {
library: Library,
info: PluginInfo,
}
struct BoxTypeEntry {
plugin_name: String,
type_info: BoxTypeInfo,
}
impl PluginRegistry {
pub fn load_plugin(&mut self, name: &str, path: &str) -> Result<(), Error> {
let lib = unsafe { Library::new(path)? };
// プラグイン初期化
let init_fn: Symbol<unsafe extern "C" fn() -> *const MathPlugin> =
unsafe { lib.get(b"nyash_plugin_init")? };
let plugin_info = unsafe { &*init_fn() };
// Box型を登録
for i in 0..plugin_info.box_count {
let box_info = unsafe { &*plugin_info.box_types.add(i) };
let box_name = unsafe { CStr::from_ptr(box_info.name).to_string_lossy() };
self.box_registry.insert(
box_name.to_string(),
BoxTypeEntry {
plugin_name: name.to_string(),
type_info: *box_info,
}
);
}
self.plugins.insert(name.to_string(), LoadedPlugin { library: lib, info: *plugin_info });
Ok(())
}
}
```
### Step 5: インタープリター統合
```rust
// src/interpreter/objects.rs
impl NyashInterpreter {
fn execute_new_dynamic(&mut self, box_name: &str, args: Vec<Box<dyn NyashBox>>)
-> Result<Box<dyn NyashBox>, RuntimeError> {
let registry = self.plugin_registry.read().unwrap();
if let Some(entry) = registry.box_registry.get(box_name) {
// 動的ライブラリ経由でコンストラクタ呼び出し
let handle = unsafe { (entry.type_info.constructor)() };
Ok(Box::new(DynamicBoxProxy {
handle,
type_name: box_name.to_string(),
type_info: entry.type_info.clone(),
}))
} else {
Err(RuntimeError::UndefinedBox { name: box_name.to_string() })
}
}
}
```
## 🎯 成功条件
1. ✅ Math/Random/Timeの全メソッドが動的ライブラリ経由で動作
2. ✅ 1つのプラグインで複数Box型を提供
3. ✅ ビルド時間がさらに30秒短縮
4. ✅ プラグイン遅延ロード(使用時のみ)
5. ✅ 静的版と同等のパフォーマンス
## 📊 ベンチマーク項目
- Math演算1000回のオーバーヘッド
- Random生成のスループット
- Time操作のレイテンシ
- プラグインロード時間(初回/キャッシュ後)
## 🔮 将来の拡張
- プラグイン自動検出plugins/ディレクトリスキャン)
- バージョン管理とアップグレード
- プラグイン間依存関係

View File

@ -0,0 +1,199 @@
# Phase 9.75f-3: 基本型動的化実験(第三段階・実験的)
## 🎯 目的
- String/Integer/Bool/Nullまで動的化する実験
- "Everything is Plugin"哲学の究極形
- ビルドを5秒以下にする野心的目標
## ⚠️ 警告
これは**実験的機能**です。以下のリスクがあります:
- 起動時間の増加(基本型ロード)
- デバッグの複雑化
- パフォーマンスオーバーヘッド
## 📋 実装計画
### Step 1: 最小コア定義
```rust
// nyash-core/src/minimal_core.rs
// 本当に必要な最小限のみ残す
pub trait MinimalBox: Send + Sync {
fn type_id(&self) -> u64;
fn as_ptr(&self) -> *const c_void;
}
// FFI境界用の最小構造
#[repr(C)]
pub struct FFIValue {
type_id: u64,
data_ptr: *mut c_void,
vtable: *const FFIVTable,
}
#[repr(C)]
pub struct FFIVTable {
drop: extern "C" fn(*mut c_void),
clone: extern "C" fn(*const c_void) -> *mut c_void,
to_string: extern "C" fn(*const c_void) -> *mut c_char,
}
```
### Step 2: 基本型プラグイン
```rust
// plugins/nyash-core-types/src/lib.rs
#[no_mangle]
extern "C" fn nyash_create_string(data: *const c_char) -> FFIValue {
let s = unsafe { CStr::from_ptr(data).to_string_lossy().to_string() };
let boxed = Box::new(StringData { value: s });
FFIValue {
type_id: STRING_TYPE_ID,
data_ptr: Box::into_raw(boxed) as *mut c_void,
vtable: &STRING_VTABLE,
}
}
static STRING_VTABLE: FFIVTable = FFIVTable {
drop: string_drop,
clone: string_clone,
to_string: string_to_string,
};
extern "C" fn string_drop(ptr: *mut c_void) {
unsafe { Box::from_raw(ptr as *mut StringData); }
}
// Integer, Bool, Null も同様に実装
```
### Step 3: 起動時プリロード
```rust
// src/main.rs
fn initialize_core_plugins() -> Result<(), Error> {
let registry = PLUGIN_REGISTRY.write().unwrap();
// 基本型は起動時に必ずロード
#[cfg(feature = "dynamic-core")]
{
registry.preload_plugin("core-types", "./plugins/libnyash_core_types.so")?;
// 基本操作をキャッシュ
registry.cache_constructor("StringBox");
registry.cache_constructor("IntegerBox");
registry.cache_constructor("BoolBox");
registry.cache_constructor("NullBox");
}
Ok(())
}
```
### Step 4: リテラル処理の最適化
```rust
// src/interpreter/expressions/literals.rs
impl NyashInterpreter {
fn evaluate_string_literal(&mut self, value: &str) -> Result<Box<dyn NyashBox>, RuntimeError> {
#[cfg(feature = "static-core")]
{
Ok(Box::new(StringBox::new(value)))
}
#[cfg(feature = "dynamic-core")]
{
// キャッシュされたコンストラクタを使用
let constructor = self.cached_constructors.get("StringBox").unwrap();
let ffi_value = unsafe {
constructor(CString::new(value)?.as_ptr())
};
Ok(Box::new(FFIBoxWrapper::new(ffi_value)))
}
}
}
```
### Step 5: JITライクな最適化
```rust
// src/interpreter/optimizer.rs
struct DynamicCallOptimizer {
// よく使われる操作をインライン化
hot_paths: HashMap<String, fn(&[FFIValue]) -> FFIValue>,
}
impl DynamicCallOptimizer {
fn optimize_hot_path(&mut self, op: &str, count: usize) {
if count > HOT_THRESHOLD {
match op {
"StringBox.concat" => {
// 頻繁に呼ばれる操作は専用パス
self.hot_paths.insert(op.to_string(), optimized_string_concat);
}
_ => {}
}
}
}
}
```
## 🎯 実験的機能
### --dynamic-all フラグ
```bash
# 通常起動(基本型は静的)
./nyash program.nyash
# 完全動的モード(実験)
./nyash --dynamic-all program.nyash
# プロファイリングモード
./nyash --dynamic-all --profile program.nyash
```
### プラグイン統計
```
Plugin Load Statistics:
core-types: 2.3ms (cached)
math: 0.8ms (lazy)
file: 1.2ms (on-demand)
Method Call Overhead:
StringBox.concat: +15ns (optimized)
IntegerBox.add: +12ns (optimized)
FileBox.read: +3ns (already dynamic)
```
## 📊 ベンチマーク目標
- Hello Worldの起動: < 10msプラグインロード込み
- 基本演算オーバーヘッド: < 20ns
- ビルド時間: 5秒以下
- バイナリサイズ: 500KB以下
## 🔮 超実験的アイデア
### ホットリロード
```rust
// 開発中にプラグインを再読み込み
./nyash --watch-plugins program.nyash
```
### WASM プラグイン
```rust
// プラグインもWASMで記述可能に
registry.load_wasm_plugin("custom-box.wasm")?;
```
### 分散プラグイン
```rust
// ネットワーク経由でプラグインロード(危険!)
registry.load_remote_plugin("https://plugins.nyash.dev/crypto-box")?;
```
## ⚠️ 既知の課題
1. **デバッグ体験**: スタックトレースが複雑化
2. **エラーメッセージ**: プラグイン境界でのエラーが分かりにくい
3. **セキュリティ**: 任意のプラグインロードは危険
4. **互換性**: プラグインABIバージョン管理が必要
## 📝 まとめ
Phase 9.75f-3は**純粋な実験**です実用性よりどこまでできるかの探求
成功すれば革新的失敗しても学びは大きい