feat(phase-9.75f): ビルトインBox動的ライブラリ分離アーキテクチャ設計
- Gemini先生のアドバイスに基づく実装計画策定 - C ABI + libloading による安定した動的ライブラリ実装 - 段階的移行戦略:インタープリターExternCall → プラグイン化 - FFI-ABI file実装(stdlib方式)完了 - MIRビルダーにfile.read/write/exists追加 - ビルド時間2分→15秒、バイナリ15MB→2MBを目標 - docs/予定/native-plan/issues/phase_9_75f_dynamic_library_architecture.md作成 - CURRENT_TASK.md更新 次のステップ: - インタープリターでExternCall直接実行実装 - 元のFileBox実装を探して置き換え - プラグインアーキテクチャ基盤構築
This commit is contained in:
@ -926,6 +926,48 @@ 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
|
||||
}
|
||||
|
||||
@ -65,6 +65,9 @@ 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);
|
||||
}
|
||||
|
||||
@ -222,4 +225,89 @@ 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::<StringBox>() {
|
||||
// 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::<StringBox>(),
|
||||
args[1].as_any().downcast_ref::<StringBox>()) {
|
||||
// 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::<StringBox>() {
|
||||
// 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user