1use lazy_static::lazy_static;
2use std::sync::Mutex;
3use std::time::{SystemTime, UNIX_EPOCH};
4
5use crate::chunk::ModuleChunk;
6use crate::value::Value;
7use crate::value::Value::*;
8use crate::vm::{VMState, VM};
9use rand::Rng;
10use std::collections::HashMap;
11
12pub type NativeFn = fn(Vec<Value>, &VM, &mut VMState, &[ModuleChunk]) -> Result<Value, String>;
15
16lazy_static! {
17 pub static ref NATIVE_FUNCTIONS: Mutex<HashMap<&'static str, (Option<usize>, NativeFn)>> =
19 Mutex::new(HashMap::from([
20 ("clock", (Some(0), clock as NativeFn)),
21 (
22 "to_string",
23 (Some(1), |args,vm,state,modules| {
24 Ok(PhoenixString(args[0].to_string(vm, state, &modules.to_vec())))
25 })
26 ),
27 (
28 "type",
29 (Some(1), |args,_,_,_| {
30 Ok(PhoenixString(args[0].get_type().to_string()))
31 })
32 ),
33 ("printf", (None, printf as NativeFn)),
34 ("int", (Some(1), int as NativeFn)),
35 ("float", (Some(1), float as NativeFn)),
36 ("rand", (Some(0), |_,_,_,_| {
37 Ok(Float(rand::random::<f32>()))
38 })),
39 ("rand_int", (Some(2), |args,_,_,_| {
40 let min = match args[0] {
41 Float(f) => f as i32,
42 Long(l) => l as i32,
43 _ => {
44 return Err(format!("Expected int or float as first argument, got {}", args[0].get_type()));
45 }
46 } as i64;
47 let max = match args[1] {
48 Float(f) => f as i32,
49 Long(l) => l as i32,
50 _ => {
51 return Err(format!("Expected int or float as second argument, got {}", args[1].get_type()));
52 }
53 } as i64;
54 if min - max == 0 {
55 return Err("min and max cannot be the same!".to_string());
56 }
57 Ok(Long(rand::thread_rng().gen_range(min..max)))
58 })),
59 ("rand_float", (Some(2), |args,_,_,_| {
60 let min = match args[0] {
61 Float(f) => f,
62 Long(l) => l as f32,
63 _ => {
64 return Err(format!("Expected int or float as first argument, got {}", args[0].get_type()));
65 }
66 };
67 let max = match args[1] {
68 Float(f) => f,
69 Long(l) => l as f32,
70 _ => {
71 return Err(format!("Expected int or float as second argument, got {}", args[1].get_type()));
72 }
73 };
74 Ok(Float(rand::thread_rng().gen_range(min..max)))
75 })),
76 ]));
77}
78
79pub fn clock(
80 _args: Vec<Value>,
81 _: &VM,
82 _: &mut VMState,
83 _: &[ModuleChunk],
84) -> Result<Value, String> {
85 let start = SystemTime::now();
86 let since_the_epoch = match start.duration_since(UNIX_EPOCH) {
87 Ok(n) => n,
88 Err(_) => {
89 return Err("Could not get time!".to_string());
90 }
91 };
92 Ok(Long(since_the_epoch.as_millis() as i64))
94}
95#[allow(dead_code)]
96pub fn value_to_string(v: &Value) -> String {
97 match v {
98 Float(x) => format!("{}", x),
99 Long(x) => format!("{}", x),
100 Bool(x) => format!("{}", x),
101 Nil => "NIL".to_string(),
102 _ => {
103 todo!("to_string() not implemented for this type")
104 }
105 }
106}
107
108fn printf(
110 args: Vec<Value>,
111 vm: &VM,
112 state: &mut VMState,
113 modules: &[ModuleChunk],
114) -> Result<Value, String> {
115 match &args[0] {
116 PhoenixPointer(p) => {
117 let s = &state.deref_string(*p).value;
118 let mut args = args.clone();
120 args.remove(0);
121 let mut i = 0;
122 let mut text = s.clone();
123 while i < text.len() {
124 if text.chars().nth(i).unwrap() == '{' && text.chars().nth(i + 1).unwrap() == '}' {
125 text.remove(i);
126 text.remove(i);
127 if args.is_empty() {
128 return Err(format!(
129 "[printf] To few arguments! Expected {} got {}!",
130 i + 1,
131 args.len()
132 ));
133 }
134 text.insert_str(
136 i,
137 &args.get(0).unwrap().to_string(vm, state, &modules.to_vec()),
138 );
139 args.remove(0);
140 }
141 i += 1;
142 }
143 println!("{}", text);
144 }
145 _ => {
146 return Err("First argument must be a string!".to_string());
147 }
148 }
149
150 Ok(Nil)
151}
152
153pub fn int(args: Vec<Value>, _: &VM, _: &mut VMState, _: &[ModuleChunk]) -> Result<Value, String> {
154 Ok(match &args[0] {
155 Float(f) => Long(*f as i64),
156 Long(l) => Long(*l),
157 Bool(b) => Long(*b as i64),
158 PhoenixString(s) => Long(match s.parse::<i64>() {
159 Ok(i) => i,
160 Err(_) => {
161 return Err(format!("Could not convert \"{s}\" to int!"));
162 }
163 }),
164 _ => {
165 return Err(format!("Could not convert {} to int!", args[0].get_type()));
166 }
167 })
168}
169
170pub fn float(
171 args: Vec<Value>,
172 _: &VM,
173 _: &mut VMState,
174 _: &[ModuleChunk],
175) -> Result<Value, String> {
176 Ok(match &args[0] {
177 Float(f) => Float(*f),
178 Long(l) => Float(*l as f32),
179 Bool(b) => Float(*b as i32 as f32),
180 PhoenixString(s) => Float(
181 match if s.ends_with('f') {
182 &s[0..s.len() - 1]
183 } else {
184 s
185 }
186 .parse::<f32>()
187 {
188 Ok(i) => i,
189 Err(_) => {
190 return Err(format!("Could not convert {} to float!", s));
191 }
192 },
193 ),
194 _ => {
195 return Err(format!(
196 "Could not convert {} to float!",
197 args[0].get_type()
198 ));
199 }
200 })
201}