From 1493ad7e94720cc08f23a323d534cab13c88b1db Mon Sep 17 00:00:00 2001 From: Moe Charm Date: Sun, 17 Aug 2025 03:50:06 +0900 Subject: [PATCH] cleanup: Remove temporary file ExternCall test code - Remove file static box from stdlib/mod.rs - Remove file.read/write/exists ExternCall handling from MIR builder - Delete test_file_ffi.nyash test file - Clean build successful --- docs/archive/gemini_dynamic_library_advice.md | 43 +++++++++ local_tests/test_file_ffi.nyash | 46 ---------- src/mir/builder.rs | 42 --------- src/stdlib/mod.rs | 88 ------------------- 4 files changed, 43 insertions(+), 176 deletions(-) create mode 100644 docs/archive/gemini_dynamic_library_advice.md delete mode 100644 local_tests/test_file_ffi.nyash diff --git a/docs/archive/gemini_dynamic_library_advice.md b/docs/archive/gemini_dynamic_library_advice.md new file mode 100644 index 00000000..a04474be --- /dev/null +++ b/docs/archive/gemini_dynamic_library_advice.md @@ -0,0 +1,43 @@ +# Gemini先生のビルトインBox動的ライブラリ化アドバイス + +2025-08-17 + +## 質問への回答 + +### 1. Rustで最も安定した動的ライブラリ実装方法は? + +現時点で最も安定し、枯れている方法は**C ABI (`#[repr(C)]`, `extern "C"`) を利用する方法**です。 + +- **理由:** C ABIはあらゆる言語とプラットフォームでサポートされている、事実上の標準 +- **実装:** `#[no_mangle]` と `extern "C"` を付け、`libloading` クレートを使用 + +### 2. `abi_stable` crateは本番環境で信頼できるか? + +**はい、信頼できる選択肢です。** ただし、まずはC ABIで実装し、制約が問題になったら移行を検討。 + +### 3. プラグイン間の依存関係管理のベストプラクティスは? + +**原則として、プラグイン間の直接的な依存は避けるべき。** +- 疎結合の維持: 各プラグインは`nyash-core`とのみ通信 +- シンボル名の衝突回避: プラグイン名をプレフィックスに + +### 4. セキュリティ(信頼できないプラグイン)の考慮は必要か? + +**はい、絶対に必要です。** +- サンドボックス: WASM実行モードを残す +- 権限モデル: Capability-based security +- 署名検証: 将来的に暗号署名 + +### 5. 実装の落とし穴や注意点は? + +- **メモリ管理:** 最大の落とし穴 + - 所有権のルールを明確に + - データ生成側が解放関数も提供 +- **`Arc>`の直接共有は不可能** + - ハンドルパターンを使用 +- **エラーハンドリング** + - ステータスコードで返す + +## 段階的移行戦略への評価 + +提案されている4フェーズの戦略は非常に現実的で、リスクが低く、素晴らしいです。 \ No newline at end of file diff --git a/local_tests/test_file_ffi.nyash b/local_tests/test_file_ffi.nyash deleted file mode 100644 index 98c8f681..00000000 --- a/local_tests/test_file_ffi.nyash +++ /dev/null @@ -1,46 +0,0 @@ -// FFI-ABI File I/O test -// 純粋FFI-ABI方式でのファイル操作デモ - -using nyashstd - -// テスト用のファイル名 -local test_file = "test_output.txt" - -// ファイルに書き込み -file.write(test_file, "Hello from Nyash FFI-ABI!\nThis is a test of file I/O.") -console.log("✅ File written: " + test_file) - -// ファイルの存在確認 -if file.exists(test_file) { - console.log("✅ File exists!") - - // ファイルを読み込み - local content = file.read(test_file) - if content != null { - console.log("✅ File content:") - console.log(content) - - // 内容を追記 - file.write(test_file, content + "\nAdded line at: " + new StringBox("timestamp")) - console.log("✅ Content appended") - - // 再度読み込み - local updated = file.read(test_file) - console.log("✅ Updated content:") - console.log(updated) - } else { - console.log("❌ Failed to read file") - } -} else { - console.log("❌ File does not exist") -} - -// 存在しないファイルを読もうとする -local missing = file.read("non_existent_file.txt") -if missing == null { - console.log("✅ Non-existent file correctly returns null") -} else { - console.log("❌ Unexpected content from non-existent file") -} - -console.log("\n🎉 FFI-ABI File I/O test complete!") \ No newline at end of file diff --git a/src/mir/builder.rs b/src/mir/builder.rs index 024c4183..2cee5c6e 100644 --- a/src/mir/builder.rs +++ b/src/mir/builder.rs @@ -926,48 +926,6 @@ impl MirBuilder { })?; return Ok(void_id); }, - ("file", "read") => { - // Generate ExternCall for file.read - let result_id = self.value_gen.next(); - self.emit_instruction(MirInstruction::ExternCall { - dst: Some(result_id), // file.read returns string - iface_name: "env.file".to_string(), - method_name: "read".to_string(), - args: arg_values, - effects: EffectMask::IO, // File operations are I/O - })?; - return Ok(result_id); - }, - ("file", "write") => { - // Generate ExternCall for file.write - self.emit_instruction(MirInstruction::ExternCall { - dst: None, // file.write is void - iface_name: "env.file".to_string(), - method_name: "write".to_string(), - args: arg_values, - effects: EffectMask::IO, // File operations are I/O - })?; - - // Return void value - let void_id = self.value_gen.next(); - self.emit_instruction(MirInstruction::Const { - dst: void_id, - value: ConstValue::Void, - })?; - return Ok(void_id); - }, - ("file", "exists") => { - // Generate ExternCall for file.exists - let result_id = self.value_gen.next(); - self.emit_instruction(MirInstruction::ExternCall { - dst: Some(result_id), // file.exists returns bool - iface_name: "env.file".to_string(), - method_name: "exists".to_string(), - args: arg_values, - effects: EffectMask::IO, // File operations are I/O - })?; - return Ok(result_id); - }, _ => { // Regular method call - continue with BoxCall } diff --git a/src/stdlib/mod.rs b/src/stdlib/mod.rs index f925ee44..83d55f37 100644 --- a/src/stdlib/mod.rs +++ b/src/stdlib/mod.rs @@ -65,9 +65,6 @@ impl BuiltinStdlib { // console static box nyashstd.static_boxes.insert("console".to_string(), Self::create_console_box()); - // file static box (FFI-ABI demonstration) - nyashstd.static_boxes.insert("file".to_string(), Self::create_file_box()); - self.namespaces.insert("nyashstd".to_string(), nyashstd); } @@ -225,89 +222,4 @@ impl BuiltinStdlib { console_box } - - /// file static boxを作成 (FFI-ABI demonstration) - fn create_file_box() -> BuiltinStaticBox { - let mut file_box = BuiltinStaticBox { - name: "file".to_string(), - methods: HashMap::new(), - }; - - // file.read(path) -> string (or null on error) - file_box.methods.insert("read".to_string(), |args| { - if args.len() != 1 { - return Err(RuntimeError::InvalidOperation { - message: "file.read() takes exactly 1 argument".to_string() - }); - } - - // StringBoxにダウンキャスト - if let Some(path_arg) = args[0].as_any().downcast_ref::() { - // Rust標準ライブラリでファイル読み込み - match std::fs::read_to_string(&path_arg.value) { - Ok(content) => Ok(Box::new(StringBox::new(content))), - Err(_) => { - // エラー時はnullを返す - use crate::boxes::NullBox; - Ok(Box::new(NullBox::new())) - } - } - } else { - Err(RuntimeError::TypeError { - message: format!("file.read() expects string argument, got {:?}", args[0].type_name()) - }) - } - }); - - // file.write(path, content) -> void - file_box.methods.insert("write".to_string(), |args| { - if args.len() != 2 { - return Err(RuntimeError::InvalidOperation { - message: "file.write() takes exactly 2 arguments".to_string() - }); - } - - // 両方の引数をStringBoxにダウンキャスト - if let (Some(path_arg), Some(content_arg)) = - (args[0].as_any().downcast_ref::(), - args[1].as_any().downcast_ref::()) { - // Rust標準ライブラリでファイル書き込み - if let Err(e) = std::fs::write(&path_arg.value, &content_arg.value) { - return Err(RuntimeError::InvalidOperation { - message: format!("Failed to write file: {}", e) - }); - } - - // VoidBoxを返す - use crate::box_trait::VoidBox; - Ok(Box::new(VoidBox::new())) - } else { - Err(RuntimeError::TypeError { - message: "file.write() expects two string arguments".to_string() - }) - } - }); - - // file.exists(path) -> bool - file_box.methods.insert("exists".to_string(), |args| { - if args.len() != 1 { - return Err(RuntimeError::InvalidOperation { - message: "file.exists() takes exactly 1 argument".to_string() - }); - } - - // StringBoxにダウンキャスト - if let Some(path_arg) = args[0].as_any().downcast_ref::() { - // Rust標準ライブラリでファイル存在確認 - let exists = std::path::Path::new(&path_arg.value).exists(); - Ok(Box::new(BoolBox::new(exists))) - } else { - Err(RuntimeError::TypeError { - message: format!("file.exists() expects string argument, got {:?}", args[0].type_name()) - }) - } - }); - - file_box - } } \ No newline at end of file