use lazy_static::lazy_static;
use std::sync::Mutex;
use crate::chunk::ModuleChunk;
use crate::value::Value::*;
use crate::value::{HeapObjVal, Value};
use crate::vm::{VMState, VM};
use std::collections::HashMap;
pub type NativeMethod =
fn(Value, Vec<Value>, &VM, &mut VMState, &[ModuleChunk]) -> Option<Result<Value, String>>;
lazy_static! {
pub static ref NATIVE_METHODS: Mutex<HashMap<&'static str, (Option<usize>, NativeMethod)>> =
Mutex::new(HashMap::from([
(
"to_string",
(Some(0), to_string as NativeMethod)
),
(
"type",
(Some(0), |this,_,_,_,_| {
Some(Ok(PhoenixString(this.get_type().to_string())))
})
),
(
"push",
(Some(1), |this, args, vm, state, modules| {
let push_string = &args[0].to_string(vm, state, &modules.to_vec());
match this {
PhoenixPointer(ptr) => {
let obj = state.deref_mut(ptr);
match obj.obj {
HeapObjVal::PhoenixList(ref mut list) => {
list.values.push(args[0].clone());
Some(Ok(Nil))
}
HeapObjVal::PhoenixString(ref mut string) => {
string.value.push_str(push_string);
Some(Ok(Nil))
}
_ => None
}
}
_ => None
}
})
),
(
"pop",
(Some(0), |this,_,_,state,_| {
match this {
PhoenixPointer(ptr) => {
let obj = state.deref_mut(ptr);
match obj.obj {
HeapObjVal::PhoenixList(ref mut list) => {
Some(Ok(list.values.pop().unwrap_or(Nil)))
}
HeapObjVal::PhoenixString(ref mut string) => {
Some(Ok(PhoenixString(string.value.pop().unwrap_or('\0').to_string())))
}
_ => None
}
}
_ => None
}
})
),
(
"len",
(Some(0), |this,_,_,state,_| {
match this {
PhoenixPointer(ptr) => {
let obj = state.deref_mut(ptr);
match obj.obj {
HeapObjVal::PhoenixList(ref mut list) => {
Some(Ok(Long(list.values.len() as i64)))
}
HeapObjVal::PhoenixString(ref mut string) => {
Some(Ok(Long(string.value.len() as i64)))
}
HeapObjVal::PhoenixHashMap(ref mut hashmap) => {
Some(Ok(Long(hashmap.map.len() as i64)))
}
_ => None
}
}
_ => None
}
})
),
(
"sort",
(Some(0), |this,_,_,state,_| {
match this {
PhoenixPointer(ptr) => {
let obj = state.deref_mut(ptr);
match obj.obj {
HeapObjVal::PhoenixList(ref mut list) => {
list.values.sort_by(|a, b| {
if let Value::Float(a) = a {
if let Value::Float(b) = b {
return a.partial_cmp(b).unwrap();
}
}
if let Value::Long(a) = a {
if let Value::Long(b) = b {
return a.partial_cmp(b).unwrap();
}
}
panic!("Attempted to sort a list with non-numeric values");
});
Some(Ok(Nil))
}
_ => None
}
}
_ => None
}
})
),
(
"get",
(Some(1), |this,args,_,state,_| {
match this {
PhoenixPointer(ptr) => {
let obj = state.deref_mut(ptr);
match obj.obj {
HeapObjVal::PhoenixHashMap(ref mut map) => {
println!("{:?}, arg: {:?}", map.map, args);
Some(Ok(map.map.get(&args[0]).unwrap_or(&Nil).clone()))
}
_ => None
}
}
_ => None
}
})
),
]));
}
fn to_string(
this: Value,
_args: Vec<Value>,
vm: &VM,
state: &mut VMState,
modules: &[ModuleChunk],
) -> Option<Result<Value, String>> {
Some(Ok(PhoenixString(this.to_string(
vm,
state,
&modules.to_vec(),
))))
}