use crate::cell;
use crate::machine::{ContFn, Machine};
#[inline]
fn mref<'a>(m: *mut Machine) -> &'a mut Machine {
unsafe { &mut *m }
}
#[unsafe(no_mangle)]
pub extern "C" fn plg_rt_step(m: *mut Machine) -> i32 {
mref(m).step() as i32
}
#[unsafe(no_mangle)]
pub extern "C" fn plg_rt_new_var(m: *mut Machine) -> u64 {
mref(m).new_var()
}
#[unsafe(no_mangle)]
pub extern "C" fn plg_rt_frame_alloc(m: *mut Machine, n: u32) -> u64 {
mref(m).frame_alloc(n as usize) as u64
}
#[unsafe(no_mangle)]
pub extern "C" fn plg_rt_frame_set(m: *mut Machine, base: u64, i: u32, w: u64) {
mref(m).heap[base as usize + i as usize] = w;
}
#[unsafe(no_mangle)]
pub extern "C" fn plg_rt_frame_get(m: *mut Machine, base: u64, i: u32) -> u64 {
mref(m).heap[base as usize + i as usize]
}
#[unsafe(no_mangle)]
pub extern "C" fn plg_rt_areg_get(m: *mut Machine, i: u32) -> u64 {
mref(m).areg[i as usize]
}
#[unsafe(no_mangle)]
pub extern "C" fn plg_rt_areg_set(m: *mut Machine, i: u32, w: u64) {
mref(m).areg[i as usize] = w;
}
#[unsafe(no_mangle)]
pub extern "C" fn plg_rt_breg_set(m: *mut Machine, i: u32, w: u64) {
mref(m).breg[i as usize] = w;
}
#[unsafe(no_mangle)]
pub extern "C" fn plg_rt_put_struct(m: *mut Machine, functor: u32, arity: u32) -> u64 {
let m = mref(m);
let idx = m.heap.len();
m.heap.push(cell::pack_functor(functor, arity));
for i in 0..arity as usize {
let w = m.breg[i];
m.heap.push(w);
}
cell::make(cell::TAG_STR, idx as u64)
}
#[unsafe(no_mangle)]
pub extern "C" fn plg_rt_put_list(m: *mut Machine, head: u64, tail: u64) -> u64 {
let m = mref(m);
let idx = m.heap.len();
m.heap.push(head);
m.heap.push(tail);
cell::make(cell::TAG_LST, idx as u64)
}
#[unsafe(no_mangle)]
pub extern "C" fn plg_rt_put_float(m: *mut Machine, bits: u64) -> u64 {
let m = mref(m);
let idx = m.heap.len();
m.heap.push(bits);
cell::make(cell::TAG_FLT, idx as u64)
}
#[unsafe(no_mangle)]
pub extern "C" fn plg_rt_put_big(m: *mut Machine, value: i64) -> u64 {
let m = mref(m);
let idx = m.heap.len();
m.heap.push(value as u64);
cell::make(cell::TAG_BIG, idx as u64)
}
#[unsafe(no_mangle)]
pub extern "C" fn plg_rt_unify(m: *mut Machine, a: u64, b: u64) -> i32 {
crate::unify::unify(mref(m), a, b) as i32
}
#[unsafe(no_mangle)]
pub extern "C" fn plg_rt_set_k(m: *mut Machine, k_fn: u64, k_env: u64) {
let m = mref(m);
m.k_fn = unsafe { std::mem::transmute::<usize, ContFn>(k_fn as usize) };
m.k_env = k_env;
}
#[unsafe(no_mangle)]
pub extern "C" fn plg_rt_k_fn(m: *mut Machine) -> u64 {
mref(m).k_fn as usize as u64
}
#[unsafe(no_mangle)]
pub extern "C" fn plg_rt_k_env(m: *mut Machine) -> u64 {
mref(m).k_env
}
#[unsafe(no_mangle)]
pub extern "C" fn plg_rt_push_cp(m: *mut Machine, retry: u64, env: u64) {
let m = mref(m);
let retry = unsafe { std::mem::transmute::<usize, ContFn>(retry as usize) };
m.push_cp(retry, env);
}
#[unsafe(no_mangle)]
pub extern "C" fn plg_rt_pred_fail(_m: *mut Machine, _env: u64) -> i32 {
0
}
#[unsafe(no_mangle)]
pub extern "C" fn plg_rt_existence_error(
m: *mut Machine,
functor: u32,
arity: u32,
site_id: u32,
) -> i32 {
let _site = crate::machine::ErrorSiteGuard::enter(m, site_id);
let m = mref(m);
let name = m.atoms.resolve(functor).to_string();
crate::errors::existence_procedure(m, &name, arity);
0
}
#[cfg(test)]
mod tests {
use super::*;
use plg_shared::StringInterner;
#[test]
fn put_struct_consumes_breg() {
let mut m = Machine::new(StringInterner::new(), Vec::new());
let mp = &mut *m as *mut Machine;
plg_rt_breg_set(mp, 0, cell::make_atom(1));
plg_rt_breg_set(mp, 1, cell::make_int(7));
let w = plg_rt_put_struct(mp, 9, 2);
assert_eq!(cell::tag_of(w), cell::TAG_STR);
let idx = cell::payload(w) as usize;
assert_eq!(cell::unpack_functor(m.heap[idx]), (9, 2));
assert_eq!(m.heap[idx + 1], cell::make_atom(1));
assert_eq!(m.heap[idx + 2], cell::make_int(7));
}
#[test]
fn frames_roundtrip() {
let mut m = Machine::new(StringInterner::new(), Vec::new());
let mp = &mut *m as *mut Machine;
let f = plg_rt_frame_alloc(mp, 3);
plg_rt_frame_set(mp, f, 2, 99);
assert_eq!(plg_rt_frame_get(mp, f, 2), 99);
}
#[test]
fn k_roundtrips_through_u64() {
let mut m = Machine::new(StringInterner::new(), Vec::new());
let mp = &mut *m as *mut Machine;
let k = plg_rt_pred_fail as *const () as usize as u64;
plg_rt_set_k(mp, k, 42);
assert_eq!(plg_rt_k_fn(mp), k);
assert_eq!(plg_rt_k_env(mp), 42);
}
}