1use crate::seqstring::global_string;
7use crate::stack::{Stack, pop, pop_two, push};
8use crate::value::Value;
9
10#[unsafe(no_mangle)]
19pub unsafe extern "C" fn patch_seq_push_float(stack: Stack, value: f64) -> Stack {
20 unsafe { push(stack, Value::Float(value)) }
21}
22
23#[unsafe(no_mangle)]
32pub unsafe extern "C" fn patch_seq_f_add(stack: Stack) -> Stack {
33 let (rest, a, b) = unsafe { pop_two(stack, "f.add") };
34 match (a, b) {
35 (Value::Float(x), Value::Float(y)) => unsafe { push(rest, Value::Float(x + y)) },
36 _ => panic!("f.add: expected two Floats on stack"),
37 }
38}
39
40#[unsafe(no_mangle)]
45pub unsafe extern "C" fn patch_seq_f_subtract(stack: Stack) -> Stack {
46 let (rest, a, b) = unsafe { pop_two(stack, "f.subtract") };
47 match (a, b) {
48 (Value::Float(x), Value::Float(y)) => unsafe { push(rest, Value::Float(x - y)) },
49 _ => panic!("f.subtract: expected two Floats on stack"),
50 }
51}
52
53#[unsafe(no_mangle)]
58pub unsafe extern "C" fn patch_seq_f_multiply(stack: Stack) -> Stack {
59 let (rest, a, b) = unsafe { pop_two(stack, "f.multiply") };
60 match (a, b) {
61 (Value::Float(x), Value::Float(y)) => unsafe { push(rest, Value::Float(x * y)) },
62 _ => panic!("f.multiply: expected two Floats on stack"),
63 }
64}
65
66#[unsafe(no_mangle)]
73pub unsafe extern "C" fn patch_seq_f_divide(stack: Stack) -> Stack {
74 let (rest, a, b) = unsafe { pop_two(stack, "f.divide") };
75 match (a, b) {
76 (Value::Float(x), Value::Float(y)) => unsafe { push(rest, Value::Float(x / y)) },
77 _ => panic!("f.divide: expected two Floats on stack"),
78 }
79}
80
81#[unsafe(no_mangle)]
94pub unsafe extern "C" fn patch_seq_f_eq(stack: Stack) -> Stack {
95 let (rest, a, b) = unsafe { pop_two(stack, "f.=") };
96 match (a, b) {
97 (Value::Float(x), Value::Float(y)) => unsafe { push(rest, Value::Bool(x == y)) },
98 _ => panic!("f.=: expected two Floats on stack"),
99 }
100}
101
102#[unsafe(no_mangle)]
107pub unsafe extern "C" fn patch_seq_f_lt(stack: Stack) -> Stack {
108 let (rest, a, b) = unsafe { pop_two(stack, "f.<") };
109 match (a, b) {
110 (Value::Float(x), Value::Float(y)) => unsafe { push(rest, Value::Bool(x < y)) },
111 _ => panic!("f.<: expected two Floats on stack"),
112 }
113}
114
115#[unsafe(no_mangle)]
120pub unsafe extern "C" fn patch_seq_f_gt(stack: Stack) -> Stack {
121 let (rest, a, b) = unsafe { pop_two(stack, "f.>") };
122 match (a, b) {
123 (Value::Float(x), Value::Float(y)) => unsafe { push(rest, Value::Bool(x > y)) },
124 _ => panic!("f.>: expected two Floats on stack"),
125 }
126}
127
128#[unsafe(no_mangle)]
133pub unsafe extern "C" fn patch_seq_f_lte(stack: Stack) -> Stack {
134 let (rest, a, b) = unsafe { pop_two(stack, "f.<=") };
135 match (a, b) {
136 (Value::Float(x), Value::Float(y)) => unsafe { push(rest, Value::Bool(x <= y)) },
137 _ => panic!("f.<=: expected two Floats on stack"),
138 }
139}
140
141#[unsafe(no_mangle)]
146pub unsafe extern "C" fn patch_seq_f_gte(stack: Stack) -> Stack {
147 let (rest, a, b) = unsafe { pop_two(stack, "f.>=") };
148 match (a, b) {
149 (Value::Float(x), Value::Float(y)) => unsafe { push(rest, Value::Bool(x >= y)) },
150 _ => panic!("f.>=: expected two Floats on stack"),
151 }
152}
153
154#[unsafe(no_mangle)]
159pub unsafe extern "C" fn patch_seq_f_neq(stack: Stack) -> Stack {
160 let (rest, a, b) = unsafe { pop_two(stack, "f.<>") };
161 match (a, b) {
162 (Value::Float(x), Value::Float(y)) => unsafe { push(rest, Value::Bool(x != y)) },
163 _ => panic!("f.<>: expected two Floats on stack"),
164 }
165}
166
167macro_rules! f_unary {
175 ($fn_name:ident, $word:literal, $method:ident) => {
176 #[unsafe(no_mangle)]
181 pub unsafe extern "C" fn $fn_name(stack: Stack) -> Stack {
182 assert!(!stack.is_null(), concat!($word, ": stack is empty"));
183 let (rest, val) = unsafe { pop(stack) };
184 match val {
185 Value::Float(x) => unsafe { push(rest, Value::Float(x.$method())) },
186 _ => panic!(concat!($word, ": expected Float on stack")),
187 }
188 }
189 };
190}
191
192macro_rules! f_const {
194 ($fn_name:ident, $value:expr) => {
195 #[unsafe(no_mangle)]
200 pub unsafe extern "C" fn $fn_name(stack: Stack) -> Stack {
201 unsafe { push(stack, Value::Float($value)) }
202 }
203 };
204}
205
206f_unary!(patch_seq_f_sqrt, "f.sqrt", sqrt);
208f_unary!(patch_seq_f_cbrt, "f.cbrt", cbrt);
209
210#[unsafe(no_mangle)]
217pub unsafe extern "C" fn patch_seq_f_pow(stack: Stack) -> Stack {
218 let (rest, a, b) = unsafe { pop_two(stack, "f.pow") };
219 match (a, b) {
220 (Value::Float(base), Value::Float(exp)) => unsafe {
221 push(rest, Value::Float(base.powf(exp)))
222 },
223 _ => panic!("f.pow: expected two Floats on stack"),
224 }
225}
226
227f_unary!(patch_seq_f_exp, "f.exp", exp);
229f_unary!(patch_seq_f_ln, "f.ln", ln);
230f_unary!(patch_seq_f_log10, "f.log10", log10);
231f_unary!(patch_seq_f_log2, "f.log2", log2);
232
233f_unary!(patch_seq_f_sin, "f.sin", sin);
235f_unary!(patch_seq_f_cos, "f.cos", cos);
236f_unary!(patch_seq_f_tan, "f.tan", tan);
237f_unary!(patch_seq_f_asin, "f.asin", asin);
238f_unary!(patch_seq_f_acos, "f.acos", acos);
239f_unary!(patch_seq_f_atan, "f.atan", atan);
240
241#[unsafe(no_mangle)]
249pub unsafe extern "C" fn patch_seq_f_atan2(stack: Stack) -> Stack {
250 let (rest, a, b) = unsafe { pop_two(stack, "f.atan2") };
251 match (a, b) {
252 (Value::Float(y), Value::Float(x)) => unsafe { push(rest, Value::Float(y.atan2(x))) },
253 _ => panic!("f.atan2: expected two Floats on stack"),
254 }
255}
256
257f_unary!(patch_seq_f_floor, "f.floor", floor);
259f_unary!(patch_seq_f_ceil, "f.ceil", ceil);
260f_unary!(patch_seq_f_round, "f.round", round_ties_even);
261f_unary!(patch_seq_f_trunc, "f.trunc", trunc);
262
263f_const!(patch_seq_f_pi, std::f64::consts::PI);
265f_const!(patch_seq_f_e, std::f64::consts::E);
266f_const!(patch_seq_f_tau, std::f64::consts::TAU);
267
268#[unsafe(no_mangle)]
277pub unsafe extern "C" fn patch_seq_int_to_float(stack: Stack) -> Stack {
278 assert!(!stack.is_null(), "int->float: stack is empty");
279 let (stack, val) = unsafe { pop(stack) };
280
281 match val {
282 Value::Int(i) => unsafe { push(stack, Value::Float(i as f64)) },
283 _ => panic!("int->float: expected Int on stack"),
284 }
285}
286
287#[unsafe(no_mangle)]
297pub unsafe extern "C" fn patch_seq_float_to_int(stack: Stack) -> Stack {
298 assert!(!stack.is_null(), "float->int: stack is empty");
299 let (stack, val) = unsafe { pop(stack) };
300
301 match val {
302 Value::Float(f) => {
303 const INT63_MAX: i64 = (1i64 << 62) - 1;
306 const INT63_MIN: i64 = -(1i64 << 62);
307 let i = if f.is_nan() {
308 0
309 } else if f >= INT63_MAX as f64 {
310 INT63_MAX
311 } else if f <= INT63_MIN as f64 {
312 INT63_MIN
313 } else {
314 f as i64
315 };
316 unsafe { push(stack, Value::Int(i)) }
317 }
318 _ => panic!("float->int: expected Float on stack"),
319 }
320}
321
322#[unsafe(no_mangle)]
327pub unsafe extern "C" fn patch_seq_float_to_string(stack: Stack) -> Stack {
328 assert!(!stack.is_null(), "float->string: stack is empty");
329 let (stack, val) = unsafe { pop(stack) };
330
331 match val {
332 Value::Float(f) => {
333 let s = f.to_string();
334 unsafe { push(stack, Value::String(global_string(s))) }
335 }
336 _ => panic!("float->string: expected Float on stack"),
337 }
338}
339
340#[unsafe(no_mangle)]
346pub unsafe extern "C" fn patch_seq_string_to_float(stack: Stack) -> Stack {
347 assert!(!stack.is_null(), "string->float: stack is empty");
348 let (stack, val) = unsafe { pop(stack) };
349
350 match val {
351 Value::String(s) => match s.as_str_or_empty().parse::<f64>() {
352 Ok(f) => {
353 let stack = unsafe { push(stack, Value::Float(f)) };
354 unsafe { push(stack, Value::Bool(true)) }
355 }
356 Err(_) => {
357 let stack = unsafe { push(stack, Value::Float(0.0)) };
358 unsafe { push(stack, Value::Bool(false)) }
359 }
360 },
361 _ => panic!("string->float: expected String on stack"),
362 }
363}
364
365pub use patch_seq_f_acos as f_acos;
370pub use patch_seq_f_add as f_add;
371pub use patch_seq_f_asin as f_asin;
372pub use patch_seq_f_atan as f_atan;
373pub use patch_seq_f_atan2 as f_atan2;
374pub use patch_seq_f_cbrt as f_cbrt;
375pub use patch_seq_f_ceil as f_ceil;
376pub use patch_seq_f_cos as f_cos;
377pub use patch_seq_f_divide as f_divide;
378pub use patch_seq_f_e as f_e;
379pub use patch_seq_f_eq as f_eq;
380pub use patch_seq_f_exp as f_exp;
381pub use patch_seq_f_floor as f_floor;
382pub use patch_seq_f_gt as f_gt;
383pub use patch_seq_f_gte as f_gte;
384pub use patch_seq_f_ln as f_ln;
385pub use patch_seq_f_log2 as f_log2;
386pub use patch_seq_f_log10 as f_log10;
387pub use patch_seq_f_lt as f_lt;
388pub use patch_seq_f_lte as f_lte;
389pub use patch_seq_f_multiply as f_multiply;
390pub use patch_seq_f_neq as f_neq;
391pub use patch_seq_f_pi as f_pi;
392pub use patch_seq_f_pow as f_pow;
393pub use patch_seq_f_round as f_round;
394pub use patch_seq_f_sin as f_sin;
395pub use patch_seq_f_sqrt as f_sqrt;
396pub use patch_seq_f_subtract as f_subtract;
397pub use patch_seq_f_tan as f_tan;
398pub use patch_seq_f_tau as f_tau;
399pub use patch_seq_f_trunc as f_trunc;
400pub use patch_seq_float_to_int as float_to_int;
401pub use patch_seq_float_to_string as float_to_string;
402pub use patch_seq_int_to_float as int_to_float;
403pub use patch_seq_push_float as push_float;
404pub use patch_seq_string_to_float as string_to_float;
405
406#[cfg(test)]
411mod tests;