2025-08-30 22:52:16 +09:00
|
|
|
use once_cell::sync::Lazy;
|
|
|
|
|
use serde_json::Value as Json;
|
2025-09-16 23:49:36 +09:00
|
|
|
use std::sync::Mutex;
|
2025-08-30 22:52:16 +09:00
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
|
|
#[no_mangle]
|
2025-09-16 23:49:36 +09:00
|
|
|
pub extern "C" fn nyash_plugin_abi() -> u32 {
|
|
|
|
|
1
|
|
|
|
|
}
|
2025-08-30 22:52:16 +09:00
|
|
|
|
|
|
|
|
#[no_mangle]
|
2025-09-16 23:49:36 +09:00
|
|
|
pub extern "C" fn nyash_plugin_init() -> i32 {
|
|
|
|
|
NYB_SUCCESS
|
|
|
|
|
}
|
2025-08-30 22:52:16 +09:00
|
|
|
|
|
|
|
|
#[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 {
|
2025-09-16 23:49:36 +09:00
|
|
|
if type_id != TYPE_ID_COMPILER {
|
|
|
|
|
return NYB_E_INVALID_METHOD;
|
|
|
|
|
}
|
2025-08-30 22:52:16 +09:00
|
|
|
match method_id {
|
|
|
|
|
METHOD_BIRTH => {
|
|
|
|
|
unsafe {
|
|
|
|
|
let mut id_g = NEXT_ID.lock().unwrap();
|
2025-09-16 23:49:36 +09:00
|
|
|
let id = *id_g;
|
|
|
|
|
*id_g += 1;
|
2025-08-30 22:52:16 +09:00
|
|
|
let need = 4usize;
|
2025-09-16 23:49:36 +09:00
|
|
|
if *result_len < need {
|
|
|
|
|
*result_len = need;
|
|
|
|
|
return NYB_E_SHORT_BUFFER;
|
|
|
|
|
}
|
2025-08-30 22:52:16 +09:00
|
|
|
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 {
|
2025-09-16 23:49:36 +09:00
|
|
|
if args.is_null() || args_len < 8 {
|
|
|
|
|
None
|
|
|
|
|
} else {
|
2025-08-30 22:52:16 +09:00
|
|
|
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() {
|
2025-09-16 23:49:36 +09:00
|
|
|
match std::str::from_utf8(&buf[8..8 + len]) {
|
2025-08-30 22:52:16 +09:00
|
|
|
Ok(s) => Some(s.to_string()),
|
2025-09-16 23:49:36 +09:00
|
|
|
Err(_) => None,
|
2025-08-30 22:52:16 +09:00
|
|
|
}
|
2025-09-16 23:49:36 +09:00
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
2025-08-30 22:52:16 +09:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
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();
|
2025-09-16 23:49:36 +09:00
|
|
|
if let Some(funcs) = module.get("functions").and_then(|v| v.as_array())
|
|
|
|
|
{
|
2025-08-30 22:52:16 +09:00
|
|
|
if let Some(fun0) = funcs.get(0) {
|
|
|
|
|
if let Some(retv) = fun0.get("return_value") {
|
2025-09-16 23:49:36 +09:00
|
|
|
if retv.is_number() {
|
|
|
|
|
ret_expr = retv.to_string();
|
|
|
|
|
} else if let Some(s) = retv.as_str() {
|
|
|
|
|
ret_expr = s.to_string();
|
|
|
|
|
}
|
2025-08-30 22:52:16 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-16 23:49:36 +09:00
|
|
|
format!(
|
|
|
|
|
"static box Generated {{\n main() {{\n return {}\n }}\n}}",
|
|
|
|
|
ret_expr
|
|
|
|
|
)
|
2025-08-30 22:52:16 +09:00
|
|
|
} 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();
|
2025-09-16 23:49:36 +09:00
|
|
|
if *result_len < need {
|
|
|
|
|
*result_len = need;
|
|
|
|
|
return NYB_E_SHORT_BUFFER;
|
|
|
|
|
}
|
2025-08-30 22:52:16 +09:00
|
|
|
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());
|
2025-09-16 23:49:36 +09:00
|
|
|
out[4..4 + bytes.len()].copy_from_slice(bytes);
|
2025-08-30 22:52:16 +09:00
|
|
|
*result_len = need;
|
|
|
|
|
}
|
|
|
|
|
NYB_SUCCESS
|
|
|
|
|
}
|
|
|
|
|
METHOD_FINI => NYB_SUCCESS,
|
|
|
|
|
_ => NYB_E_INVALID_METHOD,
|
|
|
|
|
}
|
|
|
|
|
}
|