use std::sync::OnceLock;
pub const TAG_UNIT: u64 = 0x7F00_0000_0000_0000;
pub const TAG_FALSE: u64 = 0x7F01_0000_0000_0000;
pub const TAG_TRUE: u64 = 0x7F02_0000_0000_0000;
pub const TAG_MASK: u64 = 0xFFFF_0000_0000_0000;
pub const TAG_PATTERN: u64 = 0x7F00_0000_0000_0000;
pub const PTR_MASK: u64 = 0x0000_FFFF_FFFF_FFFF;
pub const TAG_KIND_UNIT: u64 = 0x0000_0000_0000_0000;
pub const TAG_KIND_BOOL_FALSE: u64 = 0x0001_0000_0000_0000;
pub const TAG_KIND_BOOL_TRUE: u64 = 0x0002_0000_0000_0000;
pub const TAG_KIND_STRING: u64 = 0x0003_0000_0000_0000;
pub const TAG_KIND_LIST: u64 = 0x0004_0000_0000_0000;
pub const TAG_KIND_STRUCT: u64 = 0x0005_0000_0000_0000;
pub const TAG_KIND_VARIANT: u64 = 0x0006_0000_0000_0000;
pub const TAG_KIND_CLOSURE: u64 = 0x0007_0000_0000_0000;
pub const TAG_KIND_OK: u64 = 0x0008_0000_0000_0000;
pub const TAG_KIND_ERR: u64 = 0x0009_0000_0000_0000;
pub type BuiltinDispatch = unsafe extern "C" fn(
name_ptr: *const u8,
name_len: usize,
args_ptr: *const u64,
args_len: usize,
) -> u64;
static BUILTIN_DISPATCH: OnceLock<BuiltinDispatch> = OnceLock::new();
pub fn register_builtin_dispatch(f: BuiltinDispatch) {
BUILTIN_DISPATCH.set(f).ok();
}
#[inline]
pub unsafe fn call_builtin(name: &str, args: &[u64]) -> u64 {
let dispatch = BUILTIN_DISPATCH
.get()
.expect("BUILTIN_DISPATCH not registered");
dispatch(name.as_ptr(), name.len(), args.as_ptr(), args.len())
}
#[inline]
pub fn encode_f64(val: f64) -> u64 {
val.to_bits()
}
#[inline]
pub fn decode_f64(val: u64) -> f64 {
f64::from_bits(val)
}
#[inline]
pub fn is_number(val: u64) -> bool {
(val >> 56) != 0x7F
}
#[inline]
pub fn is_tagged(val: u64) -> bool {
(val >> 56) == 0x7F
}
#[inline]
pub fn encode_bool(val: bool) -> u64 {
if val {
TAG_TRUE
} else {
TAG_FALSE
}
}
#[inline]
pub fn decode_bool(val: u64) -> bool {
val == TAG_TRUE
}
#[inline]
pub const fn encode_unit() -> u64 {
TAG_UNIT
}
#[inline]
pub fn encode_heap(tag: u64, ptr: *const u8) -> u64 {
TAG_PATTERN | tag | (ptr as u64 & PTR_MASK)
}
#[inline]
pub fn decode_ptr(val: u64) -> *const u8 {
(val & PTR_MASK) as *const u8
}
#[inline]
pub fn tag_kind(val: u64) -> u64 {
val & 0x00FF_0000_0000_0000
}
pub static SYMBOL_MAP: &[(&str, &[u8])] = &[
("__ling_alloc", b"ling_alloc\0"),
("__ling_free", b"ling_free\0"),
("__ling_panic", b"ling_panic\0"),
("__ling_add", b"ling_add\0"),
("__ling_sub", b"ling_sub\0"),
("__ling_mul", b"ling_mul\0"),
("__ling_div", b"ling_div\0"),
("__ling_rem", b"ling_rem\0"),
("__ling_neg", b"ling_neg\0"),
("__ling_eq", b"ling_eq\0"),
("__ling_ne", b"ling_ne\0"),
("__ling_lt", b"ling_lt\0"),
("__ling_le", b"ling_le\0"),
("__ling_gt", b"ling_gt\0"),
("__ling_ge", b"ling_ge\0"),
("__ling_and", b"ling_and\0"),
("__ling_or", b"ling_or\0"),
("__ling_not", b"ling_not\0"),
("__ling_builtin", b"ling_builtin\0"),
("__ling_str_new", b"ling_str_new\0"),
("__ling_str_len", b"ling_str_len\0"),
("__ling_str_concat", b"ling_str_concat\0"),
("__ling_str_eq", b"ling_str_eq\0"),
("__ling_list_new", b"ling_list_new\0"),
("__ling_list_push", b"ling_list_push\0"),
("__ling_list_get", b"ling_list_get\0"),
("__ling_list_len", b"ling_list_len\0"),
("__ling_struct_new", b"ling_struct_new\0"),
("__ling_struct_get", b"ling_struct_get\0"),
("__ling_print", b"ling_print\0"),
("__ling_print_val", b"ling_print_val\0"),
("__ling_print_newline", b"ling_print_newline\0"),
("__ling_time_now", b"ling_time_now\0"),
("__ling_f64_add", b"ling_f64_add\0"),
("__ling_f64_sub", b"ling_f64_sub\0"),
("__ling_f64_mul", b"ling_f64_mul\0"),
("__ling_f64_div", b"ling_f64_div\0"),
("__ling_f64_rem", b"ling_f64_rem\0"),
("__ling_f64_neg", b"ling_f64_neg\0"),
("__ling_f64_eq", b"ling_f64_eq\0"),
("__ling_f64_lt", b"ling_f64_lt\0"),
("__ling_f64_gt", b"ling_f64_gt\0"),
("__ling_f64_le", b"ling_f64_le\0"),
("__ling_f64_ge", b"ling_f64_ge\0"),
("__ling_sin", b"ling_sin\0"),
("__ling_cos", b"ling_cos\0"),
("__ling_sqrt", b"ling_sqrt\0"),
("__ling_abs", b"ling_abs\0"),
("__ling_floor", b"ling_floor\0"),
("__ling_ceil", b"ling_ceil\0"),
("__ling_round", b"ling_round\0"),
("__ling_bool_to_u64", b"ling_bool_to_u64\0"),
];
extern "C" {
pub fn ling_f64_add(a: f64, b: f64) -> f64;
pub fn ling_f64_sub(a: f64, b: f64) -> f64;
pub fn ling_f64_mul(a: f64, b: f64) -> f64;
pub fn ling_f64_div(a: f64, b: f64) -> f64;
pub fn ling_f64_rem(a: f64, b: f64) -> f64;
pub fn ling_f64_neg(a: f64) -> f64;
pub fn ling_f64_eq(a: f64, b: f64) -> u64;
pub fn ling_f64_lt(a: f64, b: f64) -> u64;
pub fn ling_f64_gt(a: f64, b: f64) -> u64;
pub fn ling_f64_le(a: f64, b: f64) -> u64;
pub fn ling_f64_ge(a: f64, b: f64) -> u64;
pub fn ling_sin(a: f64) -> f64;
pub fn ling_cos(a: f64) -> f64;
pub fn ling_sqrt(a: f64) -> f64;
pub fn ling_abs(a: f64) -> f64;
pub fn ling_floor(a: f64) -> f64;
pub fn ling_ceil(a: f64) -> f64;
pub fn ling_round(a: f64) -> f64;
pub fn ling_bool_to_u64(b: u64) -> u64;
pub fn ling_add(a: u64, b: u64) -> u64;
pub fn ling_sub(a: u64, b: u64) -> u64;
pub fn ling_mul(a: u64, b: u64) -> u64;
pub fn ling_div(a: u64, b: u64) -> u64;
pub fn ling_rem(a: u64, b: u64) -> u64;
pub fn ling_neg(a: u64) -> u64;
pub fn ling_eq(a: u64, b: u64) -> u64;
pub fn ling_ne(a: u64, b: u64) -> u64;
pub fn ling_lt(a: u64, b: u64) -> u64;
pub fn ling_le(a: u64, b: u64) -> u64;
pub fn ling_gt(a: u64, b: u64) -> u64;
pub fn ling_ge(a: u64, b: u64) -> u64;
pub fn ling_and(a: u64, b: u64) -> u64;
pub fn ling_or(a: u64, b: u64) -> u64;
pub fn ling_not(a: u64) -> u64;
pub fn ling_alloc(size: u64) -> u64;
pub fn ling_free(ptr: u64) -> u64;
pub fn ling_panic(msg: u64);
pub fn ling_str_new(ptr: *const u8, len: usize) -> u64;
pub fn ling_str_len(val: u64) -> u64;
pub fn ling_str_concat(a: u64, b: u64) -> u64;
pub fn ling_str_eq(a: u64, b: u64) -> u64;
pub fn ling_list_new() -> u64;
pub fn ling_list_push(list: u64, val: u64) -> u64;
pub fn ling_list_get(list: u64, idx: u64) -> u64;
pub fn ling_list_len(list: u64) -> u64;
pub fn ling_struct_new(
name_ptr: *const u8,
name_len: usize,
args_ptr: *const u64,
args_len: usize,
) -> u64;
pub fn ling_struct_get(val: u64, field_ptr: *const u8, field_len: usize) -> u64;
pub fn ling_print(cstr: *const u8);
pub fn ling_print_val(val: u64);
pub fn ling_builtin(
name_ptr: *const u8,
name_len: usize,
args_ptr: *const u64,
args_len: usize,
) -> u64;
}