Skip to main content

vm/
native.rs

1use super::FnVariant;
2use crate::JITRunTime;
3use crate::memory::{alloc_dynamic, alloc_struct_bytes, take_dynamic_return};
4use anyhow::Result;
5use cranelift::prelude::AbiParam;
6use cranelift_module::{Linkage, Module};
7use dynamic::{Dynamic, Type};
8use parser::{BinaryOp, Expr, ExprKind, Span};
9use rand::RngExt;
10use std::borrow::Cow;
11use std::collections::BTreeMap;
12use std::fmt::Write as _;
13use std::sync::{Mutex, Weak};
14
15#[derive(Clone, Debug)]
16pub struct ZustCallback {
17    pub fn_ptr: usize,
18    pub ret_ty: Type,
19    pub captures: Vec<Dynamic>,
20}
21
22impl ZustCallback {
23    pub fn new(fn_ptr: usize, ret_ty: Type, captures: Vec<Dynamic>) -> Self {
24        Self { fn_ptr, ret_ty, captures }
25    }
26
27    pub fn call0(&self) -> Result<Dynamic> {
28        let args: Vec<Box<Dynamic>> = self.captures.iter().map(|value| Box::new(value.deep_clone())).collect();
29        let ptrs: Vec<*const Dynamic> = args.iter().map(|arg| arg.as_ref() as *const Dynamic).collect();
30        unsafe { call_callback(self.fn_ptr as *const u8, &self.ret_ty, &ptrs) }
31    }
32}
33
34extern "C" fn any_clone(addr: *const Dynamic) -> *const Dynamic {
35    //在堆上分配内存 复制 addr 到内存中
36    unsafe {
37        let cloned_value = (*addr).deep_clone();
38        alloc_dynamic(cloned_value)
39    }
40}
41
42extern "C" fn any_null() -> *const Dynamic {
43    //在堆上分配内存 复制 addr 到内存中
44    alloc_dynamic(Dynamic::Null)
45}
46
47extern "C" fn print(addr: *const Dynamic) {
48    if !addr.is_null() {
49        unsafe {
50            println!("{}", (*addr).to_string());
51        }
52    }
53}
54
55extern "C" fn sqrt(value: f64) -> f64 {
56    value.sqrt()
57}
58
59extern "C" fn log_any(addr: *const Dynamic) {
60    if addr.is_null() {
61        log::info!("{:?}", Dynamic::Null);
62    } else {
63        log::info!("{:?}", unsafe { &*addr });
64    }
65}
66
67extern "C" fn any_is_map(addr: *const Dynamic) -> bool {
68    !addr.is_null() && unsafe { (*addr).is_map() }
69}
70
71extern "C" fn any_is_list(addr: *const Dynamic) -> bool {
72    !addr.is_null() && unsafe { (*addr).is_list() }
73}
74
75extern "C" fn any_is_string(addr: *const Dynamic) -> bool {
76    !addr.is_null() && unsafe { (*addr).is_str() }
77}
78
79extern "C" fn any_is_null(addr: *const Dynamic) -> bool {
80    addr.is_null() || unsafe { (*addr).is_null() }
81}
82
83extern "C" fn random(start: *const Dynamic, stop: *const Dynamic) -> *const Dynamic {
84    if !start.is_null() && !stop.is_null() {
85        let mut rng = rand::rng();
86        unsafe {
87            if (&*start).is_int() {
88                let start = (*start).as_int().unwrap_or(0);
89                let stop = (*stop).as_int().unwrap_or(100);
90                return alloc_dynamic(Dynamic::I64(rng.random_range(start..stop)));
91            } else if (&*start).is_f32() || (&*start).is_f64() {
92                let start = (*start).as_float().unwrap_or(0.0);
93                let stop = (*stop).as_float().unwrap_or(1.0);
94                return alloc_dynamic(Dynamic::F64(rng.random_range(start..stop)));
95            }
96        }
97    }
98    alloc_dynamic(Dynamic::Null)
99}
100
101extern "C" fn uuid() -> *const Dynamic {
102    alloc_dynamic(uuid::Uuid::new_v4().to_string().into())
103}
104
105pub(crate) extern "C" fn struct_alloc(size: i64) -> *mut u8 {
106    let size = size.max(0) as usize;
107    let ptr = alloc_struct_bytes(size);
108    unsafe {
109        std::ptr::write_bytes(ptr, 0, size);
110    }
111    ptr
112}
113
114pub(crate) extern "C" fn repeat_fill(dst: *mut u8, pattern: u64, width: i64, len: i64) {
115    if dst.is_null() || width <= 0 || len <= 0 {
116        return;
117    }
118    let width = width as usize;
119    let len = len as usize;
120    let bytes = pattern.to_le_bytes();
121    unsafe {
122        if width == 1 {
123            std::ptr::write_bytes(dst, bytes[0], len);
124            return;
125        }
126        if !matches!(width, 2 | 4 | 8) {
127            return;
128        }
129        for idx in 0..len {
130            std::ptr::copy_nonoverlapping(bytes.as_ptr(), dst.add(idx * width), width);
131        }
132    }
133}
134
135pub(crate) extern "C" fn strcat(left: *const Dynamic, right: *const Dynamic) -> *const Dynamic {
136    let left = if left.is_null() { "" } else { unsafe { (&*left).as_str() } };
137    let right = if right.is_null() { "" } else { unsafe { (&*right).as_str() } };
138    let mut out = String::with_capacity(left.len() + right.len());
139    out.push_str(left);
140    out.push_str(right);
141    alloc_dynamic(Dynamic::StringBuf(out))
142}
143
144pub(crate) extern "C" fn strcat_i64(left: *const Dynamic, right: i64) -> *const Dynamic {
145    let left = if left.is_null() { "" } else { unsafe { (&*left).as_str() } };
146    let mut out = String::with_capacity(left.len() + 20);
147    out.push_str(left);
148    let _ = write!(&mut out, "{right}");
149    alloc_dynamic(Dynamic::StringBuf(out))
150}
151
152pub(crate) extern "C" fn strcat_assign(left: *mut Dynamic, right: *const Dynamic) -> *const Dynamic {
153    if left.is_null() {
154        return strcat(left, right);
155    }
156    let suffix = if right.is_null() {
157        Cow::Borrowed("")
158    } else if std::ptr::eq(left as *const Dynamic, right) {
159        Cow::Owned(unsafe { (&*right).to_string() })
160    } else {
161        let right = unsafe { &*right };
162        if right.is_str() { Cow::Borrowed(right.as_str()) } else { Cow::Owned(right.to_string()) }
163    };
164    unsafe {
165        match &mut *left {
166            Dynamic::StringBuf(text) => text.push_str(suffix.as_ref()),
167            Dynamic::String(text) => {
168                let mut out = String::with_capacity(text.len() + suffix.len());
169                out.push_str(text.as_str());
170                out.push_str(suffix.as_ref());
171                *left = Dynamic::StringBuf(out);
172            }
173            value => {
174                let prefix = value.to_string();
175                let mut out = String::with_capacity(prefix.len() + suffix.len());
176                out.push_str(&prefix);
177                out.push_str(suffix.as_ref());
178                *value = Dynamic::StringBuf(out);
179            }
180        }
181    }
182    left
183}
184
185pub(crate) extern "C" fn struct_from_ptr(addr: i64, ty: i64) -> *const Dynamic {
186    let ty = unsafe { (&*(ty as *const Type)).clone() };
187    alloc_dynamic(Dynamic::Struct { addr: addr as usize, ty })
188}
189
190pub(crate) extern "C" fn array_from_ptr(addr: i64, ty: i64) -> *const Dynamic {
191    if addr == 0 || ty == 0 {
192        return alloc_dynamic(Dynamic::Null);
193    }
194    let ty = unsafe { &*(ty as *const Type) };
195    alloc_dynamic(dynamic_from_ptr(addr as *const u8, ty))
196}
197
198pub(crate) extern "C" fn array_to_ptr(dst: *mut u8, value: *const Dynamic, ty: i64) {
199    if dst.is_null() || value.is_null() || ty == 0 {
200        return;
201    }
202    let ty = unsafe { &*(ty as *const Type) };
203    write_dynamic_to_ptr(dst, unsafe { &*value }, ty);
204}
205
206fn dynamic_from_ptr(addr: *const u8, ty: &Type) -> Dynamic {
207    if addr.is_null() {
208        return Dynamic::Null;
209    }
210    match ty {
211        Type::Bool => Dynamic::Bool(unsafe { std::ptr::read_unaligned(addr) } != 0),
212        Type::I8 => Dynamic::I8(unsafe { std::ptr::read_unaligned(addr as *const i8) }),
213        Type::U8 => Dynamic::U8(unsafe { std::ptr::read_unaligned(addr) }),
214        Type::I16 => Dynamic::I16(unsafe { std::ptr::read_unaligned(addr as *const i16) }),
215        Type::U16 => Dynamic::U16(unsafe { std::ptr::read_unaligned(addr as *const u16) }),
216        Type::I32 => Dynamic::I32(unsafe { std::ptr::read_unaligned(addr as *const i32) }),
217        Type::U32 => Dynamic::U32(unsafe { std::ptr::read_unaligned(addr as *const u32) }),
218        Type::I64 => Dynamic::I64(unsafe { std::ptr::read_unaligned(addr as *const i64) }),
219        Type::U64 => Dynamic::U64(unsafe { std::ptr::read_unaligned(addr as *const u64) }),
220        Type::F32 => Dynamic::F32(unsafe { std::ptr::read_unaligned(addr as *const f32) }),
221        Type::F64 => Dynamic::F64(unsafe { std::ptr::read_unaligned(addr as *const f64) }),
222        Type::Array(elem_ty, len) => {
223            let width = elem_ty.storage_width() as usize;
224            let values = (0..*len as usize).map(|idx| unsafe { dynamic_from_ptr(addr.add(idx * width), elem_ty) }).collect();
225            Dynamic::list(values)
226        }
227        Type::Struct { fields, .. } => {
228            let mut map = BTreeMap::new();
229            let (_, offsets) = Type::struct_layout(fields);
230            for ((name, field_ty), offset) in fields.iter().zip(offsets) {
231                let value = unsafe { dynamic_from_ptr(addr.add(offset as usize), field_ty) };
232                map.insert(name.clone(), value);
233            }
234            Dynamic::map(map)
235        }
236        _ => {
237            let ptr = unsafe { std::ptr::read_unaligned(addr as *const *const Dynamic) };
238            if ptr.is_null() { Dynamic::Null } else { unsafe { (&*ptr).deep_clone() } }
239        }
240    }
241}
242
243fn write_dynamic_to_ptr(dst: *mut u8, value: &Dynamic, ty: &Type) {
244    if dst.is_null() {
245        return;
246    }
247    match ty {
248        Type::Bool => unsafe { std::ptr::write_unaligned(dst, if value.is_true() { 1 } else { 0 }) },
249        Type::I8 => unsafe { std::ptr::write_unaligned(dst as *mut i8, value.clone().try_into().unwrap_or_default()) },
250        Type::U8 => unsafe { std::ptr::write_unaligned(dst, value.clone().try_into().unwrap_or_default()) },
251        Type::I16 => unsafe { std::ptr::write_unaligned(dst as *mut i16, value.clone().try_into().unwrap_or_default()) },
252        Type::U16 => unsafe { std::ptr::write_unaligned(dst as *mut u16, value.clone().try_into().unwrap_or_default()) },
253        Type::I32 => unsafe { std::ptr::write_unaligned(dst as *mut i32, value.clone().try_into().unwrap_or_default()) },
254        Type::U32 => unsafe { std::ptr::write_unaligned(dst as *mut u32, value.clone().try_into().unwrap_or_default()) },
255        Type::I64 => unsafe { std::ptr::write_unaligned(dst as *mut i64, value.clone().try_into().unwrap_or_default()) },
256        Type::U64 => unsafe { std::ptr::write_unaligned(dst as *mut u64, value.clone().try_into().unwrap_or_default()) },
257        Type::F32 => unsafe { std::ptr::write_unaligned(dst as *mut f32, f32::try_from(value.clone()).unwrap_or_default()) },
258        Type::F64 => unsafe { std::ptr::write_unaligned(dst as *mut f64, value.clone().try_into().unwrap_or_default()) },
259        Type::Array(elem_ty, len) => {
260            let width = elem_ty.storage_width() as usize;
261            for idx in 0..*len as usize {
262                let item = value.get_idx(idx).unwrap_or(Dynamic::Null);
263                unsafe { write_dynamic_to_ptr(dst.add(idx * width), &item, elem_ty) };
264            }
265        }
266        Type::Struct { fields, .. } => {
267            let (_, offsets) = Type::struct_layout(fields);
268            for ((name, field_ty), offset) in fields.iter().zip(offsets) {
269                let item = value.get_dynamic(name.as_str()).unwrap_or(Dynamic::Null);
270                unsafe { write_dynamic_to_ptr(dst.add(offset as usize), &item, field_ty) };
271            }
272        }
273        _ => {
274            let ptr = alloc_dynamic(value.deep_clone());
275            unsafe { std::ptr::write_unaligned(dst as *mut usize, ptr as usize) };
276        }
277    }
278}
279
280pub(crate) extern "C" fn import_with_vm(context: *const Weak<Mutex<JITRunTime>>, addr: *const Dynamic, path: *const Dynamic) -> bool {
281    if addr.is_null() || path.is_null() {
282        return false;
283    }
284    super::with_vm_context(context, |vm| vm.import(unsafe { &*addr }.as_str(), unsafe { &*path }.as_str())).map_err(|e| println!("import {:?}", e)).is_ok()
285}
286
287pub(crate) extern "C" fn spawn_with_vm(context: *const Weak<Mutex<JITRunTime>>, fn_name: *const Dynamic, args: *const Dynamic) -> bool {
288    if context.is_null() || fn_name.is_null() {
289        return false;
290    }
291    let fn_name = unsafe { (&*fn_name).as_str().to_string() };
292    if fn_name.is_empty() {
293        return false;
294    }
295    let args = if args.is_null() { Dynamic::Null } else { unsafe { (&*args).deep_clone() } };
296    let context = unsafe { (&*context).clone() };
297    std::thread::Builder::new()
298        .name(format!("zust:{fn_name}"))
299        .spawn(move || {
300            if let Err(err) = spawn_run(context, fn_name.as_str(), args) {
301                log::error!("spawn {fn_name} failed: {err:?}");
302            }
303        })
304        .is_ok()
305}
306
307fn spawn_args(args: Dynamic) -> Vec<Dynamic> {
308    match args {
309        Dynamic::Null => Vec::new(),
310        Dynamic::List(values) => values.read().unwrap().iter().map(Dynamic::deep_clone).collect(),
311        value => vec![value],
312    }
313}
314
315fn spawn_run(context: Weak<Mutex<JITRunTime>>, fn_name: &str, args: Dynamic) -> Result<()> {
316    let args = spawn_args(args);
317    if args.len() > 8 {
318        anyhow::bail!("spawn supports at most 8 args, got {}", args.len());
319    }
320    let arg_tys = vec![Type::Any; args.len()];
321    let (ptr, ret_ty) = super::with_vm_context(&context as *const Weak<Mutex<JITRunTime>>, |vm| vm.get_fn_ptr(fn_name, &arg_tys))?;
322    let args: Vec<Box<Dynamic>> = args.into_iter().map(Box::new).collect();
323    let ptrs: Vec<*const Dynamic> = args.iter().map(|arg| arg.as_ref() as *const Dynamic).collect();
324    unsafe {
325        call_spawned(ptr, &ret_ty, &ptrs)?;
326    }
327    Ok(())
328}
329
330pub(crate) extern "C" fn spawn_ptr(fn_ptr: i64, ret_ty: i64, args: *const Dynamic) -> bool {
331    if fn_ptr == 0 || ret_ty == 0 {
332        return false;
333    }
334    let fn_ptr = fn_ptr as usize;
335    let ret_ty = unsafe { (&*(ret_ty as *const Type)).clone() };
336    let args = if args.is_null() { Dynamic::Null } else { unsafe { (&*args).deep_clone() } };
337    std::thread::Builder::new()
338        .name("zust:closure".to_string())
339        .spawn(move || {
340            if let Err(err) = spawn_run_ptr(fn_ptr, ret_ty, args) {
341                log::error!("spawn closure failed: {err:?}");
342            }
343        })
344        .is_ok()
345}
346
347pub(crate) extern "C" fn callback_new(fn_ptr: i64, ret_ty: i64, captures: *const Dynamic) -> *const Dynamic {
348    if fn_ptr == 0 || ret_ty == 0 {
349        return alloc_dynamic(Dynamic::Null);
350    }
351    let ret_ty = unsafe { (&*(ret_ty as *const Type)).clone() };
352    let captures = if captures.is_null() {
353        Vec::new()
354    } else {
355        match unsafe { &*captures } {
356            Dynamic::List(values) => values.read().unwrap().iter().map(Dynamic::deep_clone).collect(),
357            value => vec![value.deep_clone()],
358        }
359    };
360    alloc_dynamic(Dynamic::custom(ZustCallback::new(fn_ptr as usize, ret_ty, captures)))
361}
362
363fn spawn_run_ptr(fn_ptr: usize, ret_ty: Type, args: Dynamic) -> Result<()> {
364    let args = spawn_args(args);
365    if args.len() > 8 {
366        anyhow::bail!("spawn supports at most 8 args, got {}", args.len());
367    }
368    let args: Vec<Box<Dynamic>> = args.into_iter().map(Box::new).collect();
369    let ptrs: Vec<*const Dynamic> = args.iter().map(|arg| arg.as_ref() as *const Dynamic).collect();
370    unsafe {
371        call_spawned(fn_ptr as *const u8, &ret_ty, &ptrs)?;
372    }
373    Ok(())
374}
375
376unsafe fn call_callback(ptr: *const u8, ret_ty: &Type, args: &[*const Dynamic]) -> Result<Dynamic> {
377    macro_rules! call_void {
378        () => {
379            match args {
380                [] => unsafe { std::mem::transmute::<_, extern "C" fn()>(ptr)() },
381                [a] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic)>(ptr)(*a) },
382                [a, b] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic)>(ptr)(*a, *b) },
383                [a, b, c] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c) },
384                [a, b, c, d] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c, *d) },
385                [a, b, c, d, e] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c, *d, *e) },
386                [a, b, c, d, e, f] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c, *d, *e, *f) },
387                [a, b, c, d, e, f, g] => unsafe {
388                    std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c, *d, *e, *f, *g)
389                },
390                [a, b, c, d, e, f, g, h] => unsafe {
391                    std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(
392                        *a, *b, *c, *d, *e, *f, *g, *h,
393                    )
394                },
395                _ => anyhow::bail!("callback supports at most 8 captures, got {}", args.len()),
396            }
397        };
398    }
399
400    macro_rules! call_ret {
401        ($ret:ty, $dynamic:expr) => {
402            match args {
403                [] => {
404                    let fn_ptr: extern "C" fn() -> $ret = unsafe { std::mem::transmute(ptr) };
405                    $dynamic(fn_ptr())
406                }
407                [a] => {
408                    let fn_ptr: extern "C" fn(*const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
409                    $dynamic(fn_ptr(*a))
410                }
411                [a, b] => {
412                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
413                    $dynamic(fn_ptr(*a, *b))
414                }
415                [a, b, c] => {
416                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
417                    $dynamic(fn_ptr(*a, *b, *c))
418                }
419                [a, b, c, d] => {
420                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
421                    $dynamic(fn_ptr(*a, *b, *c, *d))
422                }
423                [a, b, c, d, e] => {
424                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
425                    $dynamic(fn_ptr(*a, *b, *c, *d, *e))
426                }
427                [a, b, c, d, e, f] => {
428                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
429                    $dynamic(fn_ptr(*a, *b, *c, *d, *e, *f))
430                }
431                [a, b, c, d, e, f, g] => {
432                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
433                    $dynamic(fn_ptr(*a, *b, *c, *d, *e, *f, *g))
434                }
435                [a, b, c, d, e, f, g, h] => {
436                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
437                    $dynamic(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h))
438                }
439                _ => anyhow::bail!("callback supports at most 8 captures, got {}", args.len()),
440            }
441        };
442    }
443
444    if ret_ty.is_void() {
445        call_void!();
446        Ok(Dynamic::Null)
447    } else if ret_ty.is_bool() {
448        call_ret!(bool, |value| Ok(Dynamic::Bool(value)))
449    } else if ret_ty.is_float() {
450        if ret_ty.is_f64() { call_ret!(f64, |value| Ok(Dynamic::F64(value))) } else { call_ret!(f32, |value| Ok(Dynamic::F32(value))) }
451    } else if ret_ty.is_int() || ret_ty.is_uint() {
452        match ret_ty {
453            Type::I8 => call_ret!(i8, |value| Ok(Dynamic::I8(value))),
454            Type::U8 => call_ret!(u8, |value| Ok(Dynamic::U8(value))),
455            Type::I16 => call_ret!(i16, |value| Ok(Dynamic::I16(value))),
456            Type::U16 => call_ret!(u16, |value| Ok(Dynamic::U16(value))),
457            Type::I32 => call_ret!(i32, |value| Ok(Dynamic::I32(value))),
458            Type::U32 => call_ret!(u32, |value| Ok(Dynamic::U32(value))),
459            Type::I64 => call_ret!(i64, |value| Ok(Dynamic::I64(value))),
460            Type::U64 => call_ret!(u64, |value| Ok(Dynamic::U64(value))),
461            _ => unreachable!(),
462        }
463    } else if ret_ty.is_struct() || ret_ty.is_array() || ret_ty.is_vec() {
464        call_ret!(*const u8, |_| Ok(Dynamic::Null))
465    } else {
466        call_ret!(*const Dynamic, |ptr| unsafe { Ok((*take_dynamic_return(ptr)).deep_clone()) })
467    }
468}
469
470unsafe fn call_spawned(ptr: *const u8, ret_ty: &Type, args: &[*const Dynamic]) -> Result<()> {
471    macro_rules! call_void {
472        () => {
473            match args {
474                [] => unsafe { std::mem::transmute::<_, extern "C" fn()>(ptr)() },
475                [a] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic)>(ptr)(*a) },
476                [a, b] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic)>(ptr)(*a, *b) },
477                [a, b, c] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c) },
478                [a, b, c, d] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c, *d) },
479                [a, b, c, d, e] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c, *d, *e) },
480                [a, b, c, d, e, f] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c, *d, *e, *f) },
481                [a, b, c, d, e, f, g] => unsafe {
482                    std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c, *d, *e, *f, *g)
483                },
484                [a, b, c, d, e, f, g, h] => unsafe {
485                    std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(
486                        *a, *b, *c, *d, *e, *f, *g, *h,
487                    )
488                },
489                _ => unreachable!(),
490            }
491        };
492    }
493
494    if ret_ty.is_void() {
495        call_void!();
496        return Ok(());
497    }
498
499    macro_rules! call_ret {
500        ($ret:ty, $drop_result:expr) => {
501            match args {
502                [] => {
503                    let fn_ptr: extern "C" fn() -> $ret = unsafe { std::mem::transmute(ptr) };
504                    $drop_result(fn_ptr());
505                }
506                [a] => {
507                    let fn_ptr: extern "C" fn(*const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
508                    $drop_result(fn_ptr(*a));
509                }
510                [a, b] => {
511                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
512                    $drop_result(fn_ptr(*a, *b));
513                }
514                [a, b, c] => {
515                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
516                    $drop_result(fn_ptr(*a, *b, *c));
517                }
518                [a, b, c, d] => {
519                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
520                    $drop_result(fn_ptr(*a, *b, *c, *d));
521                }
522                [a, b, c, d, e] => {
523                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
524                    $drop_result(fn_ptr(*a, *b, *c, *d, *e));
525                }
526                [a, b, c, d, e, f] => {
527                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
528                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f));
529                }
530                [a, b, c, d, e, f, g] => {
531                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
532                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g));
533                }
534                [a, b, c, d, e, f, g, h] => {
535                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
536                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h));
537                }
538                _ => unreachable!(),
539            }
540        };
541    }
542
543    if ret_ty.is_bool() {
544        call_ret!(bool, |_| {});
545    } else if ret_ty.is_float() {
546        if ret_ty.is_f64() {
547            call_ret!(f64, |_| {});
548        } else {
549            call_ret!(f32, |_| {});
550        }
551    } else if ret_ty.is_int() || ret_ty.is_uint() {
552        match ret_ty {
553            Type::I8 => call_ret!(i8, |_| {}),
554            Type::U8 => call_ret!(u8, |_| {}),
555            Type::I16 => call_ret!(i16, |_| {}),
556            Type::U16 => call_ret!(u16, |_| {}),
557            Type::I32 => call_ret!(i32, |_| {}),
558            Type::U32 => call_ret!(u32, |_| {}),
559            Type::I64 => call_ret!(i64, |_| {}),
560            Type::U64 => call_ret!(u64, |_| {}),
561            _ => unreachable!(),
562        }
563    } else if ret_ty.is_struct() || ret_ty.is_array() || ret_ty.is_vec() {
564        call_ret!(*const u8, |_| {});
565    } else {
566        call_ret!(*const Dynamic, |ptr| drop(unsafe { take_dynamic_return(ptr) }));
567    }
568    Ok(())
569}
570
571extern "C" fn any_len(addr: *const Dynamic) -> i64 {
572    if addr.is_null() { 0 } else { unsafe { (&*addr).len() as i64 } }
573}
574
575extern "C" fn any_keys(addr: *const Dynamic) -> *const Dynamic {
576    if addr.is_null() {
577        return alloc_dynamic(Dynamic::list(Vec::new()));
578    }
579    let keys = match unsafe { &*addr } {
580        Dynamic::Map(map) => map.read().unwrap().keys().map(|key| Dynamic::from(key.as_str())).collect(),
581        _ => Vec::new(),
582    };
583    alloc_dynamic(Dynamic::list(keys))
584}
585
586extern "C" fn any_iter(addr: *const Dynamic) -> *const Dynamic {
587    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).clone().into_iter() }) }
588}
589
590extern "C" fn any_next(addr: *mut Dynamic) -> *const Dynamic {
591    alloc_dynamic(unsafe { (*addr).next().unwrap_or(Dynamic::Null) })
592}
593
594extern "C" fn any_push(addr: *mut Dynamic, value: *mut Dynamic) {
595    if !addr.is_null() && !value.is_null() {
596        unsafe {
597            (&mut *addr).push_dynamic((&*value).clone());
598        }
599    }
600}
601
602extern "C" fn any_pop(addr: *mut Dynamic) -> *const Dynamic {
603    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).pop().unwrap_or(Dynamic::Null) }) }
604}
605
606extern "C" fn get_key(addr: *const Dynamic, key: *const Dynamic) -> *const Dynamic {
607    if addr.is_null() || key.is_null() {
608        any_null()
609    } else {
610        let key: &str = unsafe { &*key }.as_str();
611        alloc_dynamic(unsafe { (*addr).get_dynamic(key).unwrap_or(Dynamic::Null) })
612    }
613}
614
615extern "C" fn del_key(addr: *const Dynamic, key: *const Dynamic) -> *const Dynamic {
616    if addr.is_null() || key.is_null() {
617        any_null()
618    } else {
619        let key: &str = unsafe { &*key }.as_str();
620        alloc_dynamic(unsafe { (*addr).remove_dynamic(key).unwrap_or(Dynamic::Null) })
621    }
622}
623
624extern "C" fn contains(addr: *const Dynamic, key: *const Dynamic) -> bool {
625    if addr.is_null() || key.is_null() {
626        false
627    } else {
628        let key: &str = unsafe { &*key }.as_str();
629        unsafe { (*addr).contains(key) }
630    }
631}
632
633extern "C" fn starts_with(addr: *const Dynamic, prefix: *const Dynamic) -> bool {
634    if addr.is_null() || prefix.is_null() {
635        false
636    } else {
637        let prefix: &str = unsafe { &*prefix }.as_str();
638        unsafe { (*addr).starts_with(prefix) }
639    }
640}
641
642extern "C" fn get_idx(addr: *const Dynamic, idx: i64) -> *const Dynamic {
643    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).get_idx(idx as usize).unwrap_or(Dynamic::Null) }) }
644}
645
646macro_rules! myvec_list_native {
647    ($push:ident, $get_idx:ident, $set_idx:ident, $vec:ident, $dynamic:ident, $ty:ty, $fallback:expr) => {
648        extern "C" fn $push(addr: *mut Dynamic, value: $ty) {
649            if addr.is_null() {
650                return;
651            }
652            unsafe {
653                match &mut *addr {
654                    Dynamic::$vec(values) => values.push(value),
655                    list => {
656                        list.push_dynamic(Dynamic::$dynamic(value));
657                    }
658                }
659            }
660        }
661
662        extern "C" fn $get_idx(addr: *const Dynamic, idx: i64) -> $ty {
663            if addr.is_null() {
664                return <$ty>::default();
665            }
666            let Ok(idx) = usize::try_from(idx) else {
667                return <$ty>::default();
668            };
669            unsafe {
670                match &*addr {
671                    Dynamic::$vec(values) => values.get(idx).unwrap_or_default(),
672                    values => values.get_idx(idx).and_then($fallback).unwrap_or_default(),
673                }
674            }
675        }
676
677        extern "C" fn $set_idx(addr: *mut Dynamic, idx: i64, value: $ty) {
678            if addr.is_null() {
679                return;
680            }
681            let Ok(idx) = usize::try_from(idx) else {
682                return;
683            };
684            unsafe {
685                match &mut *addr {
686                    Dynamic::$vec(values) => values.set(idx, value),
687                    list => list.set_idx(idx, Dynamic::$dynamic(value)),
688                }
689            }
690        }
691    };
692}
693
694macro_rules! stdvec_list_native {
695    ($push:ident, $get_idx:ident, $set_idx:ident, $vec:ident, $dynamic:ident, $ty:ty, $fallback:expr) => {
696        extern "C" fn $push(addr: *mut Dynamic, value: $ty) {
697            if addr.is_null() {
698                return;
699            }
700            unsafe {
701                match &mut *addr {
702                    Dynamic::$vec(values) => values.push(value),
703                    list => {
704                        list.push_dynamic(Dynamic::$dynamic(value));
705                    }
706                }
707            }
708        }
709
710        extern "C" fn $get_idx(addr: *const Dynamic, idx: i64) -> $ty {
711            if addr.is_null() {
712                return <$ty>::default();
713            }
714            let Ok(idx) = usize::try_from(idx) else {
715                return <$ty>::default();
716            };
717            unsafe {
718                match &*addr {
719                    Dynamic::$vec(values) => values.get(idx).copied().unwrap_or_default(),
720                    values => values.get_idx(idx).and_then($fallback).unwrap_or_default(),
721                }
722            }
723        }
724
725        extern "C" fn $set_idx(addr: *mut Dynamic, idx: i64, value: $ty) {
726            if addr.is_null() {
727                return;
728            }
729            let Ok(idx) = usize::try_from(idx) else {
730                return;
731            };
732            unsafe {
733                match &mut *addr {
734                    Dynamic::$vec(values) => {
735                        if let Some(slot) = values.get_mut(idx) {
736                            *slot = value;
737                        }
738                    }
739                    list => list.set_idx(idx, Dynamic::$dynamic(value)),
740                }
741            }
742        }
743    };
744}
745
746myvec_list_native!(list_i8_push, list_i8_get_idx, list_i8_set_idx, VecI8, I8, i8, |value: Dynamic| value.as_int().map(|value| value as i8));
747myvec_list_native!(list_u16_push, list_u16_get_idx, list_u16_set_idx, VecU16, U16, u16, |value: Dynamic| value.as_uint().map(|value| value as u16));
748myvec_list_native!(list_i16_push, list_i16_get_idx, list_i16_set_idx, VecI16, I16, i16, |value: Dynamic| value.as_int().map(|value| value as i16));
749myvec_list_native!(list_u32_push, list_u32_get_idx, list_u32_set_idx, VecU32, U32, u32, |value: Dynamic| value.as_uint().map(|value| value as u32));
750myvec_list_native!(list_i32_push, list_i32_get_idx, list_i32_set_idx, VecI32, I32, i32, |value: Dynamic| value.as_int().map(|value| value as i32));
751myvec_list_native!(list_f32_push, list_f32_get_idx, list_f32_set_idx, VecF32, F32, f32, |value: Dynamic| value.as_float().map(|value| value as f32));
752stdvec_list_native!(list_u64_push, list_u64_get_idx, list_u64_set_idx, VecU64, U64, u64, |value: Dynamic| value.as_uint());
753stdvec_list_native!(list_i64_push, list_i64_get_idx, list_i64_set_idx, VecI64, I64, i64, |value: Dynamic| value.as_int());
754stdvec_list_native!(list_f64_push, list_f64_get_idx, list_f64_set_idx, VecF64, F64, f64, |value: Dynamic| value.as_float());
755
756extern "C" fn list_bool_push(addr: *mut Dynamic, value: bool) {
757    if !addr.is_null() {
758        unsafe {
759            (&mut *addr).push_dynamic(Dynamic::Bool(value));
760        }
761    }
762}
763
764extern "C" fn list_bool_get_idx(addr: *const Dynamic, idx: i64) -> bool {
765    if addr.is_null() {
766        return false;
767    }
768    let Ok(idx) = usize::try_from(idx) else {
769        return false;
770    };
771    unsafe { (&*addr).get_idx(idx).and_then(|value| value.as_bool()).unwrap_or(false) }
772}
773
774extern "C" fn list_bool_set_idx(addr: *mut Dynamic, idx: i64, value: bool) {
775    if addr.is_null() {
776        return;
777    }
778    let Ok(idx) = usize::try_from(idx) else {
779        return;
780    };
781    unsafe {
782        (&mut *addr).set_idx(idx, Dynamic::Bool(value));
783    }
784}
785
786extern "C" fn list_u8_push(addr: *mut Dynamic, value: u8) {
787    if !addr.is_null() {
788        unsafe {
789            (&mut *addr).push_dynamic(Dynamic::U8(value));
790        }
791    }
792}
793
794extern "C" fn list_u8_get_idx(addr: *const Dynamic, idx: i64) -> u8 {
795    if addr.is_null() {
796        return 0;
797    }
798    let Ok(idx) = usize::try_from(idx) else {
799        return 0;
800    };
801    unsafe { (&*addr).get_idx(idx).and_then(|value| value.as_uint()).map(|value| value as u8).unwrap_or(0) }
802}
803
804extern "C" fn list_u8_set_idx(addr: *mut Dynamic, idx: i64, value: u8) {
805    if addr.is_null() {
806        return;
807    }
808    let Ok(idx) = usize::try_from(idx) else {
809        return;
810    };
811    unsafe {
812        (&mut *addr).set_idx(idx, Dynamic::U8(value));
813    }
814}
815
816extern "C" fn list_str_push(addr: *mut Dynamic, value: *const Dynamic) {
817    if addr.is_null() || value.is_null() {
818        return;
819    }
820    unsafe {
821        (&mut *addr).push_dynamic((&*value).clone());
822    }
823}
824
825extern "C" fn list_str_get_idx(addr: *const Dynamic, idx: i64) -> *const Dynamic {
826    if addr.is_null() {
827        return any_null();
828    };
829    let Ok(idx) = usize::try_from(idx) else {
830        return any_null();
831    };
832    if let Some(value) = unsafe { (&*addr).get_idx(idx) } { alloc_dynamic(value) } else { any_null() }
833}
834
835extern "C" fn list_str_set_idx(addr: *mut Dynamic, idx: i64, value: *const Dynamic) {
836    if addr.is_null() || value.is_null() {
837        return;
838    }
839    let Ok(idx) = usize::try_from(idx) else {
840        return;
841    };
842    unsafe {
843        (&mut *addr).set_idx(idx, (&*value).clone());
844    }
845}
846
847extern "C" fn slice(addr: *const Dynamic, start: i64, stop: *const Dynamic, inclusive: bool) -> *const Dynamic {
848    if addr.is_null() {
849        return any_null();
850    }
851
852    let value = unsafe { &*addr };
853    let len = value.len() as i64;
854    let start = start.clamp(0, len) as usize;
855    let mut stop = if stop.is_null() {
856        len
857    } else {
858        let raw = unsafe { &*stop };
859        if raw.is_null() { len } else { raw.as_int().unwrap_or(len) }
860    };
861    if inclusive && stop < len {
862        stop += 1;
863    }
864    let stop = stop.clamp(start as i64, len) as usize;
865
866    let sliced = if value.is_str() {
867        Dynamic::from(value.as_str().chars().skip(start).take(stop.saturating_sub(start)).collect::<String>())
868    } else {
869        match value {
870            Dynamic::List(list) => Dynamic::list(list.read().unwrap()[start..stop].to_vec()),
871            _ => Dynamic::Null,
872        }
873    };
874    alloc_dynamic(sliced)
875}
876
877extern "C" fn set_key(addr: *mut Dynamic, key: *const Dynamic, value: *const Dynamic) {
878    if addr.is_null() || key.is_null() {
879        return;
880    }
881    let key: &str = unsafe { &*key }.as_str();
882    unsafe { (&mut *addr).set_dynamic(key.into(), (&*value).clone()) }
883}
884
885extern "C" fn set_idx(addr: *mut Dynamic, idx: i64, value: *const Dynamic) {
886    if addr.is_null() {
887        return;
888    }
889    unsafe { (&mut *addr).set_idx(idx as usize, (&*value).clone()) }
890}
891
892extern "C" fn any_from_i64(v: i64) -> *const Dynamic {
893    alloc_dynamic(Dynamic::I64(v))
894}
895
896extern "C" fn any_from_bool(v: bool) -> *const Dynamic {
897    alloc_dynamic(Dynamic::Bool(v))
898}
899
900extern "C" fn any_to_i64(addr: *const Dynamic) -> i64 {
901    if addr.is_null() {
902        return 0;
903    }
904    unsafe {
905        let value = &*addr;
906        value.as_int().or_else(|| value.as_float().map(|value| value as i64)).unwrap_or(0)
907    }
908}
909
910extern "C" fn any_to_bool(addr: *const Dynamic) -> bool {
911    if addr.is_null() {
912        return false;
913    }
914    unsafe {
915        let value = &*addr;
916        if let Some(v) = value.as_bool() {
917            v
918        } else if let Some(v) = value.as_int() {
919            v != 0
920        } else if let Some(v) = value.as_float() {
921            v != 0.0
922        } else {
923            !value.is_null()
924        }
925    }
926}
927
928extern "C" fn any_from_f64(v: f64) -> *const Dynamic {
929    alloc_dynamic(Dynamic::F64(v))
930}
931
932extern "C" fn any_split(addr: *mut Dynamic, s: *const Dynamic) -> *const Dynamic {
933    if addr.is_null() || s.is_null() {
934        return any_null();
935    }
936    let s: &str = unsafe { &*s }.as_str();
937    alloc_dynamic(unsafe { (&*addr).clone() }.split(s))
938}
939
940extern "C" fn any_to_f64(addr: *const Dynamic) -> f64 {
941    if addr.is_null() {
942        return 0.0;
943    }
944    unsafe { (&*addr).as_float().unwrap_or(0.0) }
945}
946
947extern "C" fn any_to_string(addr: *const Dynamic) -> *const Dynamic {
948    if addr.is_null() {
949        return alloc_dynamic(Dynamic::from(""));
950    }
951    alloc_dynamic(Dynamic::from(unsafe { &*addr }.to_string()))
952}
953
954extern "C" fn any_binary(left: *const Dynamic, op: i32, right: *const Dynamic) -> *const Dynamic {
955    if left.is_null() {
956        if right.is_null() {
957            return any_null();
958        }
959        return alloc_dynamic(unsafe { (&*right).clone() });
960    }
961    if right.is_null() {
962        return alloc_dynamic(unsafe { (&*left).clone() });
963    }
964    let op = BinaryOp::try_from(op).unwrap();
965    if op == BinaryOp::Add {
966        let (left_value, right_value) = unsafe { (&*left, &*right) };
967        if left_value.is_str() || right_value.is_str() {
968            return alloc_dynamic(left_value.clone() + right_value.clone());
969        }
970    }
971    unsafe {
972        let expr = Expr::new(
973            ExprKind::Binary { left: Box::new(Expr::new(ExprKind::Value((&*left).clone()), Span::default())), op, right: Box::new(Expr::new(ExprKind::Value((&*right).clone()), Span::default())) },
974            Span::default(),
975        );
976        alloc_dynamic(expr.compact().unwrap_or(Dynamic::Null))
977    }
978}
979
980extern "C" fn any_logic(left: *const Dynamic, op: i32, right: *const Dynamic) -> i32 {
981    let op = BinaryOp::try_from(op).unwrap();
982    unsafe {
983        let expr = Expr::new(
984            ExprKind::Binary { left: Box::new(Expr::new(ExprKind::Value((&*left).clone()), Span::default())), op, right: Box::new(Expr::new(ExprKind::Value((&*right).clone()), Span::default())) },
985            Span::default(),
986        );
987        if expr.compact().and_then(|r| r.as_bool()).unwrap_or(false) { 1 } else { 0 }
988    }
989}
990
991pub const STD: [(&str, &[Type], Type, *const u8); 5] = [
992    ("print", &[Type::Any], Type::Void, print as *const u8),
993    ("sqrt", &[Type::F64], Type::F64, sqrt as *const u8),
994    ("log", &[Type::Any], Type::Void, log_any as *const u8),
995    ("uuid", &[], Type::Any, uuid as *const u8),
996    ("rand", &[Type::Any, Type::Any], Type::Any, random as *const u8),
997];
998
999pub const ANY: [(&str, &[Type], Type, *const u8); 66] = [
1000    ("Any::null", &[], Type::Any, any_null as *const u8),
1001    ("Any::is_map", &[Type::Any], Type::Bool, any_is_map as *const u8),
1002    ("Any::is_list", &[Type::Any], Type::Bool, any_is_list as *const u8),
1003    ("Any::is_string", &[Type::Any], Type::Bool, any_is_string as *const u8),
1004    ("Any::is_null", &[Type::Any], Type::Bool, any_is_null as *const u8),
1005    ("Any::clone", &[Type::Any], Type::Any, any_clone as *const u8),
1006    ("Any::len", &[Type::Any], Type::I32, any_len as *const u8),
1007    ("Any::keys", &[Type::Any], Type::Any, any_keys as *const u8),
1008    ("Any::split", &[Type::Any, Type::Any], Type::Any, any_split as *const u8),
1009    ("Any::push", &[Type::Any, Type::Any], Type::Void, any_push as *const u8),
1010    ("Any::pop", &[Type::Any], Type::Any, any_pop as *const u8),
1011    ("Any::get_idx", &[Type::Any, Type::I64], Type::Any, get_idx as *const u8),
1012    ("Any::push_bool", &[Type::Any, Type::Bool], Type::Void, list_bool_push as *const u8),
1013    ("Any::get_idx_bool", &[Type::Any, Type::I64], Type::Bool, list_bool_get_idx as *const u8),
1014    ("Any::set_idx_bool", &[Type::Any, Type::I64, Type::Bool], Type::Void, list_bool_set_idx as *const u8),
1015    ("Any::push_u8", &[Type::Any, Type::U8], Type::Void, list_u8_push as *const u8),
1016    ("Any::get_idx_u8", &[Type::Any, Type::I64], Type::U8, list_u8_get_idx as *const u8),
1017    ("Any::set_idx_u8", &[Type::Any, Type::I64, Type::U8], Type::Void, list_u8_set_idx as *const u8),
1018    ("Any::push_i8", &[Type::Any, Type::I8], Type::Void, list_i8_push as *const u8),
1019    ("Any::get_idx_i8", &[Type::Any, Type::I64], Type::I8, list_i8_get_idx as *const u8),
1020    ("Any::set_idx_i8", &[Type::Any, Type::I64, Type::I8], Type::Void, list_i8_set_idx as *const u8),
1021    ("Any::push_u16", &[Type::Any, Type::U16], Type::Void, list_u16_push as *const u8),
1022    ("Any::get_idx_u16", &[Type::Any, Type::I64], Type::U16, list_u16_get_idx as *const u8),
1023    ("Any::set_idx_u16", &[Type::Any, Type::I64, Type::U16], Type::Void, list_u16_set_idx as *const u8),
1024    ("Any::push_i16", &[Type::Any, Type::I16], Type::Void, list_i16_push as *const u8),
1025    ("Any::get_idx_i16", &[Type::Any, Type::I64], Type::I16, list_i16_get_idx as *const u8),
1026    ("Any::set_idx_i16", &[Type::Any, Type::I64, Type::I16], Type::Void, list_i16_set_idx as *const u8),
1027    ("Any::push_u32", &[Type::Any, Type::U32], Type::Void, list_u32_push as *const u8),
1028    ("Any::get_idx_u32", &[Type::Any, Type::I64], Type::U32, list_u32_get_idx as *const u8),
1029    ("Any::set_idx_u32", &[Type::Any, Type::I64, Type::U32], Type::Void, list_u32_set_idx as *const u8),
1030    ("Any::push_i32", &[Type::Any, Type::I32], Type::Void, list_i32_push as *const u8),
1031    ("Any::get_idx_i32", &[Type::Any, Type::I64], Type::I32, list_i32_get_idx as *const u8),
1032    ("Any::set_idx_i32", &[Type::Any, Type::I64, Type::I32], Type::Void, list_i32_set_idx as *const u8),
1033    ("Any::push_f32", &[Type::Any, Type::F32], Type::Void, list_f32_push as *const u8),
1034    ("Any::get_idx_f32", &[Type::Any, Type::I64], Type::F32, list_f32_get_idx as *const u8),
1035    ("Any::set_idx_f32", &[Type::Any, Type::I64, Type::F32], Type::Void, list_f32_set_idx as *const u8),
1036    ("Any::push_u64", &[Type::Any, Type::U64], Type::Void, list_u64_push as *const u8),
1037    ("Any::get_idx_u64", &[Type::Any, Type::I64], Type::U64, list_u64_get_idx as *const u8),
1038    ("Any::set_idx_u64", &[Type::Any, Type::I64, Type::U64], Type::Void, list_u64_set_idx as *const u8),
1039    ("Any::push_i64", &[Type::Any, Type::I64], Type::Void, list_i64_push as *const u8),
1040    ("Any::get_idx_i64", &[Type::Any, Type::I64], Type::I64, list_i64_get_idx as *const u8),
1041    ("Any::set_idx_i64", &[Type::Any, Type::I64, Type::I64], Type::Void, list_i64_set_idx as *const u8),
1042    ("Any::push_f64", &[Type::Any, Type::F64], Type::Void, list_f64_push as *const u8),
1043    ("Any::get_idx_f64", &[Type::Any, Type::I64], Type::F64, list_f64_get_idx as *const u8),
1044    ("Any::set_idx_f64", &[Type::Any, Type::I64, Type::F64], Type::Void, list_f64_set_idx as *const u8),
1045    ("Any::push_str", &[Type::Any, Type::Str], Type::Void, list_str_push as *const u8),
1046    ("Any::get_idx_str", &[Type::Any, Type::I64], Type::Str, list_str_get_idx as *const u8),
1047    ("Any::set_idx_str", &[Type::Any, Type::I64, Type::Str], Type::Void, list_str_set_idx as *const u8),
1048    ("Any::slice", &[Type::Any, Type::I64, Type::Any, Type::Bool], Type::Any, slice as *const u8),
1049    ("Any::contains", &[Type::Any, Type::Any], Type::Bool, contains as *const u8),
1050    ("Any::starts_with", &[Type::Any, Type::Any], Type::Bool, starts_with as *const u8),
1051    ("Any::get_key", &[Type::Any, Type::Any], Type::Any, get_key as *const u8),
1052    ("Any::del_key", &[Type::Any, Type::Any], Type::Any, del_key as *const u8),
1053    ("Any::set_idx", &[Type::Any, Type::I64, Type::Any], Type::Void, set_idx as *const u8),
1054    ("Any::set_key", &[Type::Any, Type::Any, Type::Any], Type::Void, set_key as *const u8),
1055    ("Any::from_i64", &[Type::I64], Type::Any, any_from_i64 as *const u8),
1056    ("Any::from_bool", &[Type::Bool], Type::Any, any_from_bool as *const u8),
1057    ("Any::to_i64", &[Type::Any], Type::I64, any_to_i64 as *const u8),
1058    ("Any::to_bool", &[Type::Any], Type::Bool, any_to_bool as *const u8),
1059    ("Any::from_f64", &[Type::F64], Type::Any, any_from_f64 as *const u8),
1060    ("Any::to_f64", &[Type::Any], Type::F64, any_to_f64 as *const u8),
1061    ("Any::to_string", &[Type::Any], Type::Str, any_to_string as *const u8),
1062    ("Any::binary", &[Type::Any, Type::I32, Type::Any], Type::Any, any_binary as *const u8),
1063    ("Any::logic", &[Type::Any, Type::I32, Type::Any], Type::Bool, any_logic as *const u8),
1064    ("Any::iter", &[Type::Any], Type::Any, any_iter as *const u8),
1065    ("Any::next", &[Type::Any], Type::Any, any_next as *const u8),
1066];
1067
1068use std::rc::Rc;
1069impl JITRunTime {
1070    pub fn add_native_ptr(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type, fn_ptr: *const u8) -> Result<u32> {
1071        self.native_symbols.write().unwrap().insert(full_name.to_string(), fn_ptr as usize);
1072        self.add_native(full_name, name, arg_tys, ret_ty)
1073    }
1074
1075    pub(crate) fn add_context_native_ptr(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type, fn_ptr: *const u8) -> Result<u32> {
1076        self.native_symbols.write().unwrap().insert(full_name.to_string(), fn_ptr as usize);
1077        self.add_context_native(full_name, name, arg_tys, ret_ty)
1078    }
1079
1080    pub fn add_native(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type) -> Result<u32> {
1081        let fn_ty = Type::Fn { tys: arg_tys.to_vec(), ret: Rc::new(ret_ty.clone()) };
1082        let id = self.compiler.add_symbol(name, compiler::Symbol::Native(fn_ty.clone()));
1083        let sig = self.get_sig(arg_tys, ret_ty)?;
1084        let fn_id = self.module.declare_function(full_name, Linkage::Import, &sig)?;
1085        self.fns.insert(id, FnVariant::Native { ty: fn_ty, fn_id, context: None });
1086        Ok(id)
1087    }
1088
1089    pub(crate) fn add_context_native(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type) -> Result<u32> {
1090        let fn_ty = Type::Fn { tys: arg_tys.to_vec(), ret: Rc::new(ret_ty.clone()) };
1091        let id = self.compiler.add_symbol(name, compiler::Symbol::Native(fn_ty.clone()));
1092        let mut sig = self.module.make_signature();
1093        sig.params.push(AbiParam::new(crate::ptr_type()));
1094        for arg in arg_tys.iter() {
1095            sig.params.push(AbiParam::new(crate::get_type(arg)?));
1096        }
1097        if !ret_ty.is_void() {
1098            sig.returns.push(AbiParam::new(crate::get_type(&ret_ty)?));
1099        }
1100        let fn_id = self.module.declare_function(full_name, Linkage::Import, &sig)?;
1101        self.fns.insert(id, FnVariant::Native { ty: fn_ty, fn_id, context: Some(self.owner_context_ptr()) });
1102        Ok(id)
1103    }
1104}