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