1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
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;
/// Format: self, args, vm, vm_state, modules, if it returns none, this function doesnt support the type
/// Note: self is not mutable, because its the Pointer to the object, or a "primitive" value
pub type NativeMethod =
fn(Value, Vec<Value>, &VM, &mut VMState, &[ModuleChunk]) -> Option<Result<Value, String>>;
lazy_static! {
/// Format: name, (arity, function) if arity is None, the function is variadic
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| {
// prepare a string in case we need it
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(),
))))
}