use std::cmp::Ordering;
use crate::vmbindings::nativeval::NativeValue;
use crate::vmbindings::value::Value;
use crate::vmbindings::vm::Vm;
pub extern "C" fn constructor(cvm: *mut Vm, nargs: u16) {
let vm = unsafe { &mut *cvm };
if nargs == 0 {
vm.stack.push(Value::Array(vm.malloc(Vec::new())).wrap());
return;
}
let nargs = nargs as usize;
let array = vm.malloc(Vec::with_capacity(nargs));
for _i in 0..nargs {
let val = vm.stack.pop().unwrap();
array.as_mut().push(val.clone());
}
vm.stack.push(Value::Array(array).wrap());
}
#[hana_function()]
fn length(array: Value::Array) -> Value {
Value::Int(array.as_ref().len() as i64)
}
#[hana_function()]
fn insert_(array: Value::Array, pos: Value::Int, elem: Value::Any) -> Value {
array.as_mut().insert(pos as usize, elem.wrap());
Value::Int(array.as_ref().len() as i64)
}
#[hana_function()]
fn delete_(array: Value::Array, from_pos: Value::Int, nelems: Value::Int) -> Value {
array
.as_mut()
.drain((from_pos as usize)..((nelems as usize) + 1));
Value::Int(array.as_ref().len() as i64)
}
#[hana_function()]
fn push(array: Value::Array, elem: Value::Any) -> Value {
array.as_mut().push(elem.wrap());
Value::Nil
}
#[hana_function()]
fn pop(array: Value::Array) -> Value {
unsafe { array.as_mut().pop().unwrap().unwrap() }
}
extern "C" {
fn value_gt(left: NativeValue, right: NativeValue) -> NativeValue;
fn value_lt(left: NativeValue, right: NativeValue) -> NativeValue;
}
fn value_cmp(left: &NativeValue, right: &NativeValue) -> Ordering {
let left = left.clone();
let right = right.clone();
match unsafe { value_gt(left, right).unwrap() } {
Value::Int(1) => Ordering::Greater,
_ => match unsafe { value_lt(left, right).unwrap() } {
Value::Int(1) => Ordering::Less,
_ => Ordering::Equal,
},
}
}
#[hana_function()]
fn sort(array: Value::Array) -> Value {
let new_array = vm.malloc(array.as_ref().clone());
let slice = new_array.as_mut().as_mut_slice();
slice.sort_by(value_cmp);
Value::Array(new_array)
}
#[hana_function()]
fn sort_(array: Value::Array) -> Value {
let slice = array.as_mut().as_mut_slice();
slice.sort_by(value_cmp);
Value::Array(array)
}
#[hana_function()]
fn map(array: Value::Array, fun: Value::Any) -> Value {
let new_array = vm.malloc(Vec::with_capacity(array.as_ref().len()));
let mut args = Vec::with_capacity(1);
for val in array.as_ref().iter() {
args.clear();
args.push(val.clone());
if let Some(val) = vm.call(fun.wrap(), &args) {
new_array.as_mut().push(val);
} else {
return Value::PropagateError;
}
}
Value::Array(new_array)
}
#[hana_function()]
fn filter(array: Value::Array, fun: Value::Any) -> Value {
let new_array = vm.malloc(Vec::new());
let mut args = Vec::with_capacity(1);
for val in array.as_ref().iter() {
args.clear();
args.push(val.clone());
if let Some(filter) = vm.call(fun.wrap(), &args) {
if unsafe { filter.unwrap() }.is_true(vm) {
new_array.as_mut().push(val.clone());
}
} else {
return Value::PropagateError;
}
}
Value::Array(new_array)
}
#[hana_function()]
fn reduce(array: Value::Array, fun: Value::Any, acc_: Value::Any) -> Value {
let mut acc = acc_.clone();
let mut args = Vec::with_capacity(2);
for val in array.as_ref().iter() {
args.clear();
args.push(acc.wrap().clone());
args.push(val.clone());
if let Some(val) = vm.call(fun.wrap(), &args) {
acc = unsafe { val.unwrap() };
} else {
return Value::PropagateError;
}
}
acc
}
extern "C" {
fn value_eq(left: NativeValue, right: NativeValue) -> NativeValue;
}
#[hana_function()]
fn index(array: Value::Array, elem: Value::Any) -> Value {
let array = array.as_ref();
for i in 0..(array.len() - 1) {
match unsafe { value_eq(array[i], elem.wrap()).unwrap() } {
Value::Int(1) => return Value::Int(i as i64),
_ => (),
}
}
Value::Int(-1)
}
#[hana_function()]
fn join(array: Value::Array, delim: Value::Str) -> Value {
let mut s = String::new();
let array = array.as_ref();
if array.len() > 0 {
s += unsafe { format!("{}", array[0].unwrap()).as_str() };
}
if array.len() > 1 {
let mut i = 1;
while i < array.len() {
s += delim.as_ref();
s += unsafe { format!("{}", array[i].unwrap()).as_str() };
i += 1;
}
}
Value::Str(vm.malloc(s.into()))
}