Files
hakorune/plugins/nyash-python-compiler-plugin/src/lib.rs
nyash-codex 9bdf2ff069 chore: Phase 25.2関連ドキュメント更新&レガシーテストアーカイブ整理
## ドキュメント更新
- CURRENT_TASK.md: Phase 25.2完了記録
- phase-25.1b/e/q/25.2 README更新
- json_v0_bridge/README.md新規追加

## テストファイル整理
- vtable_*テストをtests/archive/に移動(6ファイル)
- json_program_loop.rsテスト追加

## コード整理
- プラグイン(egui/python-compiler)微修正
- benchmarks.rs, instance_v2.rs更新
- MIR関連ファイル微調整

## 全体成果
Phase 25.2完了により:
- LoopSnapshotMergeBox統一管理実装
- ValueId(1283)バグ根本解決
- ~35行コード削減(目標210行の16%)
- 11テスト全部PASS、3実行テストケースPASS
2025-11-20 03:56:12 +09:00

260 lines
10 KiB
Rust

use once_cell::sync::Lazy;
use serde_json::Value as Json;
use std::sync::Mutex;
const NYB_SUCCESS: i32 = 0;
const NYB_E_INVALID_METHOD: i32 = -3;
const NYB_E_SHORT_BUFFER: i32 = -1;
const TYPE_ID_COMPILER: u32 = 61;
const METHOD_BIRTH: u32 = 0;
const METHOD_COMPILE: u32 = 1;
const METHOD_FINI: u32 = u32::MAX;
static NEXT_ID: Lazy<Mutex<u32>> = Lazy::new(|| Mutex::new(1));
// legacy v1 abi/init removed
/* legacy v1 entry removed
#[no_mangle]
pub extern "C" fn nyash_plugin_invoke(
type_id: u32,
method_id: u32,
_instance_id: u32,
args: *const u8,
args_len: usize,
result: *mut u8,
result_len: *mut usize,
) -> i32 {
if type_id != TYPE_ID_COMPILER {
return NYB_E_INVALID_METHOD;
}
match method_id {
METHOD_BIRTH => {
unsafe {
let mut id_g = NEXT_ID.lock().unwrap();
let id = *id_g;
*id_g += 1;
let need = 4usize;
if *result_len < need {
*result_len = need;
return NYB_E_SHORT_BUFFER;
}
let out = std::slice::from_raw_parts_mut(result, *result_len);
out[0..4].copy_from_slice(&(id as u32).to_le_bytes());
*result_len = need;
}
NYB_SUCCESS
}
METHOD_COMPILE => {
// Decode TLV first string arg as JSON IR
let ir = unsafe {
if args.is_null() || args_len < 8 {
None
} else {
let buf = std::slice::from_raw_parts(args, args_len);
let tag = u16::from_le_bytes([buf[4], buf[5]]);
let len = u16::from_le_bytes([buf[6], buf[7]]) as usize;
if tag == 6 && 8 + len <= buf.len() {
match std::str::from_utf8(&buf[8..8 + len]) {
Ok(s) => Some(s.to_string()),
Err(_) => None,
}
} else {
None
}
}
};
let nyash_source = if let Some(s) = ir.or_else(|| std::env::var("NYASH_PY_IR").ok()) {
// Minimal: accept either {"nyash_source": "..."} shortcut, or a tiny IR
match serde_json::from_str::<Json>(&s).ok() {
Some(Json::Object(map)) => {
if let Some(Json::String(src)) = map.get("nyash_source") {
src.clone()
} else if let Some(module) = map.get("module") {
// Try module.functions[0].name and maybe return value
let mut ret_expr = "0".to_string();
if let Some(funcs) = module.get("functions").and_then(|v| v.as_array())
{
if let Some(fun0) = funcs.get(0) {
if let Some(retv) = fun0.get("return_value") {
if retv.is_number() {
ret_expr = retv.to_string();
} else if let Some(s) = retv.as_str() {
ret_expr = s.to_string();
}
}
}
}
format!(
"static box Generated {{\n main() {{\n return {}\n }}\n}}",
ret_expr
)
} else {
"static box Generated { main() { return 0 } }".to_string()
}
}
_ => "static box Generated { main() { return 0 } }".to_string(),
}
} else {
"static box Generated { main() { return 0 } }".to_string()
};
unsafe {
let bytes = nyash_source.as_bytes();
let need = 4 + bytes.len();
if *result_len < need {
*result_len = need;
return NYB_E_SHORT_BUFFER;
}
let out = std::slice::from_raw_parts_mut(result, *result_len);
out[0..2].copy_from_slice(&6u16.to_le_bytes());
out[2..4].copy_from_slice(&(bytes.len() as u16).to_le_bytes());
out[4..4 + bytes.len()].copy_from_slice(bytes);
*result_len = need;
}
NYB_SUCCESS
}
METHOD_FINI => NYB_SUCCESS,
_ => NYB_E_INVALID_METHOD,
}
}
*/
// ===== TypeBox ABI v2 (resolve/invoke_id) =====
#[repr(C)]
pub struct NyashTypeBoxFfi {
pub abi_tag: u32, // 'TYBX'
pub version: u16, // 1
pub struct_size: u16, // sizeof(NyashTypeBoxFfi)
pub name: *const std::os::raw::c_char,
pub resolve: Option<extern "C" fn(*const std::os::raw::c_char) -> u32>,
pub invoke_id: Option<extern "C" fn(u32, u32, *const u8, usize, *mut u8, *mut usize) -> i32>,
pub capabilities: u64,
}
unsafe impl Sync for NyashTypeBoxFfi {}
use std::ffi::CStr;
extern "C" fn pycompiler_resolve(name: *const std::os::raw::c_char) -> u32 {
if name.is_null() {
return 0;
}
let s = unsafe { CStr::from_ptr(name) }.to_string_lossy();
match s.as_ref() {
"birth" => METHOD_BIRTH,
"compile" => METHOD_COMPILE,
"fini" => METHOD_FINI,
_ => 0,
}
}
extern "C" fn pycompiler_invoke_id(
_instance_id: u32,
method_id: u32,
args: *const u8,
args_len: usize,
result: *mut u8,
result_len: *mut usize,
) -> i32 {
match method_id {
METHOD_BIRTH => unsafe {
let mut id_g = NEXT_ID.lock().unwrap();
let id = *id_g;
*id_g += 1;
if result_len.is_null() {
return NYB_E_SHORT_BUFFER;
}
let need = 4usize;
if *result_len < need {
*result_len = need;
return NYB_E_SHORT_BUFFER;
}
let out = std::slice::from_raw_parts_mut(result, *result_len);
out[0..4].copy_from_slice(&(id as u32).to_le_bytes());
*result_len = need;
NYB_SUCCESS
},
METHOD_COMPILE => unsafe {
let ir = if args.is_null() || args_len < 8 {
None
} else {
let buf = std::slice::from_raw_parts(args, args_len);
let tag = u16::from_le_bytes([buf[4], buf[5]]);
let len = u16::from_le_bytes([buf[6], buf[7]]) as usize;
if tag == 6 && 8 + len <= buf.len() {
std::str::from_utf8(&buf[8..8 + len])
.ok()
.map(|s| s.to_string())
} else {
None
}
};
let nyash_source = if let Some(s) = ir.or_else(|| std::env::var("NYASH_PY_IR").ok()) {
match serde_json::from_str::<Json>(&s).ok() {
Some(Json::Object(map)) => {
if let Some(Json::String(src)) = map.get("nyash_source") {
src.clone()
} else if let Some(module) = map.get("module") {
let mut ret_expr = "0".to_string();
if let Some(funcs) = module.get("functions").and_then(|v| v.as_array())
{
if let Some(fun0) = funcs.get(0) {
if let Some(retv) = fun0.get("return_value") {
if retv.is_number() {
ret_expr = retv.to_string();
} else if let Some(s) = retv.as_str() {
ret_expr = s.to_string();
}
}
}
}
// static box Generated {
// main() {
// return <ret_expr>
// }
// }
// フォーマット文字列中のリテラル波括弧はすべてエスケープする。
format!(
"static box Generated {{\n main() {{\n return {}\n }}\n}}\n",
ret_expr
)
} else {
"static box Generated { main() { return 0 } }".to_string()
}
}
_ => "static box Generated { main() { return 0 } }".to_string(),
}
} else {
"static box Generated { main() { return 0 } }".to_string()
};
let bytes = nyash_source.as_bytes();
if result_len.is_null() {
return NYB_E_SHORT_BUFFER;
}
let need = 4 + bytes.len();
if *result_len < need {
*result_len = need;
return NYB_E_SHORT_BUFFER;
}
let out = std::slice::from_raw_parts_mut(result, *result_len);
out[0..2].copy_from_slice(&6u16.to_le_bytes());
out[2..4].copy_from_slice(&(bytes.len() as u16).to_le_bytes());
out[4..4 + bytes.len()].copy_from_slice(bytes);
*result_len = need;
NYB_SUCCESS
},
METHOD_FINI => NYB_SUCCESS,
_ => NYB_E_INVALID_METHOD,
}
}
#[no_mangle]
pub static nyash_typebox_PythonCompilerBox: NyashTypeBoxFfi = NyashTypeBoxFfi {
abi_tag: 0x54594258,
version: 1,
struct_size: std::mem::size_of::<NyashTypeBoxFfi>() as u16,
name: b"PythonCompilerBox\0".as_ptr() as *const std::os::raw::c_char,
resolve: Some(pycompiler_resolve),
invoke_id: Some(pycompiler_invoke_id),
capabilities: 0,
};