use crate::seqstring::global_string;
use crate::stack::{Stack, pop, pop_two, push};
use crate::value::Value;
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_push_float(stack: Stack, value: f64) -> Stack {
unsafe { push(stack, Value::Float(value)) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_f_add(stack: Stack) -> Stack {
let (rest, a, b) = unsafe { pop_two(stack, "f.add") };
match (a, b) {
(Value::Float(x), Value::Float(y)) => unsafe { push(rest, Value::Float(x + y)) },
_ => panic!("f.add: expected two Floats on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_f_subtract(stack: Stack) -> Stack {
let (rest, a, b) = unsafe { pop_two(stack, "f.subtract") };
match (a, b) {
(Value::Float(x), Value::Float(y)) => unsafe { push(rest, Value::Float(x - y)) },
_ => panic!("f.subtract: expected two Floats on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_f_multiply(stack: Stack) -> Stack {
let (rest, a, b) = unsafe { pop_two(stack, "f.multiply") };
match (a, b) {
(Value::Float(x), Value::Float(y)) => unsafe { push(rest, Value::Float(x * y)) },
_ => panic!("f.multiply: expected two Floats on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_f_divide(stack: Stack) -> Stack {
let (rest, a, b) = unsafe { pop_two(stack, "f.divide") };
match (a, b) {
(Value::Float(x), Value::Float(y)) => unsafe { push(rest, Value::Float(x / y)) },
_ => panic!("f.divide: expected two Floats on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_f_eq(stack: Stack) -> Stack {
let (rest, a, b) = unsafe { pop_two(stack, "f.=") };
match (a, b) {
(Value::Float(x), Value::Float(y)) => unsafe { push(rest, Value::Bool(x == y)) },
_ => panic!("f.=: expected two Floats on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_f_lt(stack: Stack) -> Stack {
let (rest, a, b) = unsafe { pop_two(stack, "f.<") };
match (a, b) {
(Value::Float(x), Value::Float(y)) => unsafe { push(rest, Value::Bool(x < y)) },
_ => panic!("f.<: expected two Floats on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_f_gt(stack: Stack) -> Stack {
let (rest, a, b) = unsafe { pop_two(stack, "f.>") };
match (a, b) {
(Value::Float(x), Value::Float(y)) => unsafe { push(rest, Value::Bool(x > y)) },
_ => panic!("f.>: expected two Floats on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_f_lte(stack: Stack) -> Stack {
let (rest, a, b) = unsafe { pop_two(stack, "f.<=") };
match (a, b) {
(Value::Float(x), Value::Float(y)) => unsafe { push(rest, Value::Bool(x <= y)) },
_ => panic!("f.<=: expected two Floats on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_f_gte(stack: Stack) -> Stack {
let (rest, a, b) = unsafe { pop_two(stack, "f.>=") };
match (a, b) {
(Value::Float(x), Value::Float(y)) => unsafe { push(rest, Value::Bool(x >= y)) },
_ => panic!("f.>=: expected two Floats on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_f_neq(stack: Stack) -> Stack {
let (rest, a, b) = unsafe { pop_two(stack, "f.<>") };
match (a, b) {
(Value::Float(x), Value::Float(y)) => unsafe { push(rest, Value::Bool(x != y)) },
_ => panic!("f.<>: expected two Floats on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_int_to_float(stack: Stack) -> Stack {
assert!(!stack.is_null(), "int->float: stack is empty");
let (stack, val) = unsafe { pop(stack) };
match val {
Value::Int(i) => unsafe { push(stack, Value::Float(i as f64)) },
_ => panic!("int->float: expected Int on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_float_to_int(stack: Stack) -> Stack {
assert!(!stack.is_null(), "float->int: stack is empty");
let (stack, val) = unsafe { pop(stack) };
match val {
Value::Float(f) => {
const INT63_MAX: i64 = (1i64 << 62) - 1;
const INT63_MIN: i64 = -(1i64 << 62);
let i = if f.is_nan() {
0
} else if f >= INT63_MAX as f64 {
INT63_MAX
} else if f <= INT63_MIN as f64 {
INT63_MIN
} else {
f as i64
};
unsafe { push(stack, Value::Int(i)) }
}
_ => panic!("float->int: expected Float on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_float_to_string(stack: Stack) -> Stack {
assert!(!stack.is_null(), "float->string: stack is empty");
let (stack, val) = unsafe { pop(stack) };
match val {
Value::Float(f) => {
let s = f.to_string();
unsafe { push(stack, Value::String(global_string(s))) }
}
_ => panic!("float->string: expected Float on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_string_to_float(stack: Stack) -> Stack {
assert!(!stack.is_null(), "string->float: stack is empty");
let (stack, val) = unsafe { pop(stack) };
match val {
Value::String(s) => match s.as_str().parse::<f64>() {
Ok(f) => {
let stack = unsafe { push(stack, Value::Float(f)) };
unsafe { push(stack, Value::Bool(true)) }
}
Err(_) => {
let stack = unsafe { push(stack, Value::Float(0.0)) };
unsafe { push(stack, Value::Bool(false)) }
}
},
_ => panic!("string->float: expected String on stack"),
}
}
pub use patch_seq_f_add as f_add;
pub use patch_seq_f_divide as f_divide;
pub use patch_seq_f_eq as f_eq;
pub use patch_seq_f_gt as f_gt;
pub use patch_seq_f_gte as f_gte;
pub use patch_seq_f_lt as f_lt;
pub use patch_seq_f_lte as f_lte;
pub use patch_seq_f_multiply as f_multiply;
pub use patch_seq_f_neq as f_neq;
pub use patch_seq_f_subtract as f_subtract;
pub use patch_seq_float_to_int as float_to_int;
pub use patch_seq_float_to_string as float_to_string;
pub use patch_seq_int_to_float as int_to_float;
pub use patch_seq_push_float as push_float;
pub use patch_seq_string_to_float as string_to_float;
#[cfg(test)]
mod tests;