1use super::FnVariant;
2use crate::JITRunTime;
3use anyhow::Result;
4use cranelift::prelude::AbiParam;
5use cranelift_module::{Linkage, Module};
6use dynamic::{Dynamic, Type};
7use parser::{BinaryOp, Expr, ExprKind, Span};
8use rand::RngExt;
9use std::sync::{Mutex, Weak};
10
11extern "C" fn any_clone(addr: *const Dynamic) -> *const Dynamic {
12 unsafe {
14 let cloned_value = (*addr).deep_clone();
15 let ptr = Box::new(cloned_value);
16 Box::into_raw(ptr)
17 }
18}
19
20extern "C" fn any_null() -> *const Dynamic {
21 let ptr = Box::new(Dynamic::Null);
23 Box::into_raw(ptr)
24}
25
26extern "C" fn print(addr: *const Dynamic) {
27 if !addr.is_null() {
28 unsafe {
29 println!("{}", (*addr).to_string());
30 }
31 }
32}
33
34extern "C" fn any_is_map(addr: *const Dynamic) -> bool {
35 !addr.is_null() && unsafe { (*addr).is_map() }
36}
37
38extern "C" fn any_is_list(addr: *const Dynamic) -> bool {
39 !addr.is_null() && unsafe { (*addr).is_list() }
40}
41
42extern "C" fn random(start: *const Dynamic, stop: *const Dynamic) -> *const Dynamic {
43 if !start.is_null() && !stop.is_null() {
44 let mut rng = rand::rng();
45 unsafe {
46 if (&*start).is_int() {
47 let start = (*start).as_int().unwrap_or(0);
48 let stop = (*stop).as_int().unwrap_or(100);
49 return Box::into_raw(Box::new(Dynamic::I64(rng.random_range(start..stop))));
50 } else if (&*start).is_f32() || (&*start).is_f64() {
51 let start = (*start).as_float().unwrap_or(0.0);
52 let stop = (*stop).as_float().unwrap_or(1.0);
53 return Box::into_raw(Box::new(Dynamic::F64(rng.random_range(start..stop))));
54 }
55 }
56 }
57 Box::into_raw(Box::new(Dynamic::Null))
58}
59
60extern "C" fn uuid() -> *const Dynamic {
61 Box::into_raw(Box::new(uuid::Uuid::new_v4().to_string().into()))
62}
63
64extern "C" fn struct_alloc(size: i64) -> *mut u8 {
65 let size = size.max(0) as usize;
66 let mut buf = vec![0u8; size].into_boxed_slice();
67 let ptr = buf.as_mut_ptr();
68 std::mem::forget(buf);
69 ptr
70}
71
72extern "C" fn struct_from_ptr(addr: i64, ty: i64) -> *const Dynamic {
73 let ty = unsafe { (&*(ty as *const Type)).clone() };
74 Box::into_raw(Box::new(Dynamic::Struct { addr: addr as usize, ty }))
75}
76
77pub(crate) extern "C" fn import_with_vm(context: *const Weak<Mutex<JITRunTime>>, addr: *const Dynamic, path: *const Dynamic) -> bool {
78 if addr.is_null() || path.is_null() {
79 return false;
80 }
81 super::with_vm_context(context, |vm| vm.import(unsafe { &*addr }.as_str(), unsafe { &*path }.as_str())).map_err(|e| println!("import {:?}", e)).is_ok()
82}
83
84extern "C" fn any_len(addr: *const Dynamic) -> i64 {
85 if addr.is_null() { 0 } else { unsafe { (&*addr).len() as i64 } }
86}
87
88extern "C" fn any_keys(addr: *const Dynamic) -> *const Dynamic {
89 if addr.is_null() {
90 return Box::into_raw(Box::new(Dynamic::list(Vec::new())));
91 }
92 let keys = match unsafe { &*addr } {
93 Dynamic::Map(map) => map.read().unwrap().keys().map(|key| Dynamic::from(key.as_str())).collect(),
94 _ => Vec::new(),
95 };
96 Box::into_raw(Box::new(Dynamic::list(keys)))
97}
98
99extern "C" fn any_iter(addr: *const Dynamic) -> *const Dynamic {
100 if addr.is_null() {
101 &Dynamic::Null
102 } else {
103 let v = unsafe { Box::new((*addr).clone().into_iter()) };
104 Box::into_raw(v)
105 }
106}
107
108extern "C" fn any_next(addr: *mut Dynamic) -> *const Dynamic {
109 let v = unsafe { Box::new((*addr).next().unwrap_or(Dynamic::Null)) };
110 Box::into_raw(v)
111}
112
113extern "C" fn any_push(addr: *mut Dynamic, value: *mut Dynamic) {
114 if !addr.is_null() && !value.is_null() {
115 unsafe {
116 (&mut *addr).push((&*value).clone());
117 }
118 }
119}
120
121extern "C" fn any_pop(addr: *mut Dynamic) -> *const Dynamic {
122 if addr.is_null() {
123 &Dynamic::Null
124 } else {
125 let v = unsafe { Box::new((*addr).pop().unwrap_or(Dynamic::Null)) };
126 Box::into_raw(v)
127 }
128}
129
130extern "C" fn get_key(addr: *const Dynamic, key: *const Dynamic) -> *const Dynamic {
131 if addr.is_null() || key.is_null() {
132 &Dynamic::Null
133 } else {
134 let key: &str = unsafe { &*key }.as_str();
135 let v = unsafe { Box::new((*addr).get_dynamic(key).unwrap_or(Dynamic::Null)) };
136 Box::into_raw(v)
137 }
138}
139
140extern "C" fn del_key(addr: *const Dynamic, key: *const Dynamic) -> *const Dynamic {
141 if addr.is_null() || key.is_null() {
142 &Dynamic::Null
143 } else {
144 let key: &str = unsafe { &*key }.as_str();
145 let v = unsafe { Box::new((*addr).remove_dynamic(key).unwrap_or(Dynamic::Null)) };
146 Box::into_raw(v)
147 }
148}
149
150extern "C" fn contains(addr: *const Dynamic, key: *const Dynamic) -> bool {
151 if addr.is_null() || key.is_null() {
152 false
153 } else {
154 let key: &str = unsafe { &*key }.as_str();
155 unsafe { (*addr).contains(key) }
156 }
157}
158
159extern "C" fn starts_with(addr: *const Dynamic, prefix: *const Dynamic) -> bool {
160 if addr.is_null() || prefix.is_null() {
161 false
162 } else {
163 let prefix: &str = unsafe { &*prefix }.as_str();
164 unsafe { (*addr).starts_with(prefix) }
165 }
166}
167
168extern "C" fn get_idx(addr: *const Dynamic, idx: i64) -> *const Dynamic {
169 if addr.is_null() {
170 &Dynamic::Null
171 } else {
172 let v = unsafe { Box::new((*addr).get_idx(idx as usize).unwrap_or(Dynamic::Null)) };
173 Box::into_raw(v)
174 }
175}
176
177extern "C" fn slice(addr: *const Dynamic, start: i64, stop: *const Dynamic, inclusive: bool) -> *const Dynamic {
178 if addr.is_null() {
179 return &Dynamic::Null;
180 }
181
182 let value = unsafe { &*addr };
183 let len = value.len() as i64;
184 let start = start.clamp(0, len) as usize;
185 let mut stop = if stop.is_null() {
186 len
187 } else {
188 let raw = unsafe { &*stop };
189 if raw.is_null() { len } else { raw.as_int().unwrap_or(len) }
190 };
191 if inclusive && stop < len {
192 stop += 1;
193 }
194 let stop = stop.clamp(start as i64, len) as usize;
195
196 let sliced = match value {
197 Dynamic::String(text) => Dynamic::from(text.chars().skip(start).take(stop.saturating_sub(start)).collect::<String>()),
198 Dynamic::List(list) => Dynamic::list(list.read().unwrap()[start..stop].to_vec()),
199 _ => Dynamic::Null,
200 };
201 Box::into_raw(Box::new(sliced))
202}
203
204extern "C" fn set_key(addr: *mut Dynamic, key: *const Dynamic, value: *const Dynamic) {
205 if addr.is_null() || key.is_null() {
206 return;
207 }
208 let key: &str = unsafe { &*key }.as_str();
209 unsafe { (&mut *addr).set_dynamic(key.into(), (&*value).clone()) }
210}
211
212extern "C" fn set_idx(addr: *mut Dynamic, idx: i64, value: *const Dynamic) {
213 if addr.is_null() {
214 return;
215 }
216 unsafe { (&mut *addr).set_idx(idx as usize, (&*value).clone()) }
217}
218
219extern "C" fn any_from_i64(v: i64) -> *const Dynamic {
220 let value = Box::new(Dynamic::I64(v));
221 Box::into_raw(value)
222}
223
224extern "C" fn any_from_bool(v: bool) -> *const Dynamic {
225 let value = Box::new(Dynamic::Bool(v));
226 Box::into_raw(value)
227}
228
229extern "C" fn any_to_i64(addr: *const Dynamic) -> i64 {
230 if addr.is_null() {
231 return 0;
232 }
233 unsafe { (&*addr).as_int().unwrap_or(0) }
234}
235
236extern "C" fn any_to_bool(addr: *const Dynamic) -> bool {
237 if addr.is_null() {
238 return false;
239 }
240 unsafe {
241 let value = &*addr;
242 if let Some(v) = value.as_bool() {
243 v
244 } else if let Some(v) = value.as_int() {
245 v != 0
246 } else if let Some(v) = value.as_float() {
247 v != 0.0
248 } else {
249 !value.is_null()
250 }
251 }
252}
253
254extern "C" fn any_from_f64(v: f64) -> *const Dynamic {
255 let value = Box::new(Dynamic::F64(v));
256 Box::into_raw(value)
257}
258
259extern "C" fn any_split(addr: *mut Dynamic, s: *const Dynamic) -> *const Dynamic {
260 if addr.is_null() || s.is_null() {
261 return &Dynamic::Null;
262 }
263 let s: &str = unsafe { &*s }.as_str();
264 Box::into_raw(Box::new(unsafe { (&*addr).clone() }.split(s)))
265}
266
267extern "C" fn any_to_f64(addr: *const Dynamic) -> f64 {
268 if addr.is_null() {
269 return 0.0;
270 }
271 unsafe { (&*addr).as_float().unwrap_or(0.0) }
272}
273
274extern "C" fn any_to_string(addr: *const Dynamic) -> *const Dynamic {
275 if addr.is_null() {
276 return Box::into_raw(Box::new(Dynamic::from("")));
277 }
278 Box::into_raw(Box::new(Dynamic::from(unsafe { &*addr }.to_string())))
279}
280
281extern "C" fn any_binary(left: *const Dynamic, op: i32, right: *const Dynamic) -> *const Dynamic {
282 if left.is_null() {
283 return right;
284 }
285 if right.is_null() {
286 return left;
287 }
288 let op = BinaryOp::try_from(op).unwrap();
289 unsafe {
290 let expr = Expr::new(
291 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())) },
292 Span::default(),
293 );
294 let r = Box::new(expr.compact().unwrap_or(Dynamic::Null));
295 Box::into_raw(r)
296 }
297}
298
299extern "C" fn any_logic(left: *const Dynamic, op: i32, right: *const Dynamic) -> i32 {
300 let op = BinaryOp::try_from(op).unwrap();
301 unsafe {
302 let expr = Expr::new(
303 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())) },
304 Span::default(),
305 );
306 if expr.compact().and_then(|r| r.as_bool()).unwrap_or(false) { 1 } else { 0 }
307 }
308}
309
310pub const STD: [(&str, &[Type], Type, *const u8); 5] = [
311 ("print", &[Type::Any], Type::Void, print as *const u8),
312 ("uuid", &[], Type::Any, uuid as *const u8),
313 ("rand", &[Type::Any, Type::Any], Type::Any, random as *const u8),
314 ("__struct_alloc", &[Type::I64], Type::Any, struct_alloc as *const u8),
315 ("__struct_from_ptr", &[Type::I64, Type::I64], Type::Any, struct_from_ptr as *const u8),
316];
317
318pub const ANY: [(&str, &[Type], Type, *const u8); 28] = [
319 ("Any::null", &[], Type::Any, any_null as *const u8),
320 ("Any::is_map", &[Type::Any], Type::Bool, any_is_map as *const u8),
321 ("Any::is_list", &[Type::Any], Type::Bool, any_is_list as *const u8),
322 ("Any::clone", &[Type::Any], Type::Any, any_clone as *const u8),
323 ("Any::len", &[Type::Any], Type::I32, any_len as *const u8),
324 ("Any::keys", &[Type::Any], Type::Any, any_keys as *const u8),
325 ("Any::split", &[Type::Any, Type::Any], Type::Any, any_split as *const u8),
326 ("Any::push", &[Type::Any, Type::Any], Type::Void, any_push as *const u8),
327 ("Any::pop", &[Type::Any], Type::Any, any_pop as *const u8),
328 ("Any::get_idx", &[Type::Any, Type::I64], Type::Any, get_idx as *const u8),
329 ("Any::slice", &[Type::Any, Type::I64, Type::Any, Type::Bool], Type::Any, slice as *const u8),
330 ("Any::contains", &[Type::Any, Type::Any], Type::Bool, contains as *const u8),
331 ("Any::starts_with", &[Type::Any, Type::Any], Type::Bool, starts_with as *const u8),
332 ("Any::get_key", &[Type::Any, Type::Any], Type::Any, get_key as *const u8),
333 ("Any::del_key", &[Type::Any, Type::Any], Type::Any, del_key as *const u8),
334 ("Any::set_idx", &[Type::Any, Type::I64, Type::Any], Type::Void, set_idx as *const u8),
335 ("Any::set_key", &[Type::Any, Type::Any, Type::Any], Type::Void, set_key as *const u8),
336 ("Any::from_i64", &[Type::I64], Type::Any, any_from_i64 as *const u8),
337 ("Any::from_bool", &[Type::Bool], Type::Any, any_from_bool as *const u8),
338 ("Any::to_i64", &[Type::Any], Type::I64, any_to_i64 as *const u8),
339 ("Any::to_bool", &[Type::Any], Type::Bool, any_to_bool as *const u8),
340 ("Any::from_f64", &[Type::F64], Type::Any, any_from_f64 as *const u8),
341 ("Any::to_f64", &[Type::Any], Type::F64, any_to_f64 as *const u8),
342 ("Any::to_string", &[Type::Any], Type::Str, any_to_string as *const u8),
343 ("Any::binary", &[Type::Any, Type::I32, Type::Any], Type::Any, any_binary as *const u8),
344 ("Any::logic", &[Type::Any, Type::I32, Type::Any], Type::Bool, any_logic as *const u8),
345 ("Any::iter", &[Type::Any], Type::Any, any_iter as *const u8),
346 ("Any::next", &[Type::Any], Type::Any, any_next as *const u8),
347];
348
349use std::rc::Rc;
350impl JITRunTime {
351 pub fn add_native_ptr(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type, fn_ptr: *const u8) -> Result<u32> {
352 self.native_symbols.write().unwrap().insert(full_name.to_string(), fn_ptr as usize);
353 self.add_native(full_name, name, arg_tys, ret_ty)
354 }
355
356 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> {
357 self.native_symbols.write().unwrap().insert(full_name.to_string(), fn_ptr as usize);
358 self.add_context_native(full_name, name, arg_tys, ret_ty)
359 }
360
361 pub fn add_native(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type) -> Result<u32> {
362 let fn_ty = Type::Fn { tys: arg_tys.to_vec(), ret: Rc::new(ret_ty.clone()) };
363 let id = self.compiler.add_symbol(name, compiler::Symbol::Native(fn_ty.clone()));
364 let sig = self.get_sig(arg_tys, ret_ty)?;
365 let fn_id = self.module.declare_function(full_name, Linkage::Import, &sig)?;
366 self.fns.insert(id, FnVariant::Native { ty: fn_ty, fn_id, context: None });
367 Ok(id)
368 }
369
370 pub(crate) fn add_context_native(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type) -> Result<u32> {
371 let fn_ty = Type::Fn { tys: arg_tys.to_vec(), ret: Rc::new(ret_ty.clone()) };
372 let id = self.compiler.add_symbol(name, compiler::Symbol::Native(fn_ty.clone()));
373 let mut sig = self.module.make_signature();
374 sig.params.push(AbiParam::new(crate::ptr_type()));
375 for arg in arg_tys.iter() {
376 sig.params.push(AbiParam::new(crate::get_type(arg)?));
377 }
378 if !ret_ty.is_void() {
379 sig.returns.push(AbiParam::new(crate::get_type(&ret_ty)?));
380 }
381 let fn_id = self.module.declare_function(full_name, Linkage::Import, &sig)?;
382 self.fns.insert(id, FnVariant::Native { ty: fn_ty, fn_id, context: Some(self.owner_context_ptr()) });
383 Ok(id)
384 }
385}