1use neige_infra::math::float_to_integer;
2
3use crate::{state::LuaState, value::value::LuaValue};
4use neige_infra::LuaArith as Arith;
5
6pub trait ArithApi {
7 fn arith(&mut self, op: Arith);
8}
9
10impl ArithApi for LuaState {
11 fn arith(&mut self, op: Arith) {
12 let b = self.stack_pop();
13 let a = if op == Arith::Unm || op == Arith::BNot {
14 b.clone()
15 } else {
16 self.stack_pop()
17 };
18 let c = a.clone();
19 let d = b.clone();
20 let result = match op {
21 Arith::Add => do_arith(a, b, |x, y| x + y, |x, y| x + y),
22 Arith::Sub => do_arith(a, b, |x, y| x - y, |x, y| x - y),
23 Arith::Mul => do_arith(a, b, |x, y| x * y, |x, y| x * y),
24 Arith::Mod => do_arith(a, b, |x, y| x % y, |x, y| x % y),
25 Arith::Pow => do_arith_f(a, b, |x, y| x.powf(y)),
26 Arith::Div => do_arith_f(a, b, |x, y| x / y),
27 Arith::IDiv => do_arith(a, b, |x, y| x.div_euclid(y), |x, y| x.div_euclid(y)),
28 Arith::BAnd => do_arith_i(a, b, |x, y| x & y),
29 Arith::Bor => do_arith_i(a, b, |x, y| x | y),
30 Arith::BXor => do_arith_i(a, b, |x, y| x ^ y),
31 Arith::Shl => do_arith_i(a, b, |x, n| if n > 0 { x << n } else { x >> -n }),
32 Arith::Shr => do_arith_i(a, b, |x, n| if n > 0 { x >> n } else { x << -n }),
33 Arith::Unm => do_arith(a, b, |x, _| -x, |x, _| -x),
34 Arith::BNot => do_arith_i(a, b, |x, _| !x),
35 };
36 if let Some(res) = result {
37 self.stack_push(res);
38 return;
39 }
40 let result = self.call_meta_method(c, d, op.get_meta_name().into());
41 if let Some(res) = result {
42 self.stack_push(res);
43 return;
44 }
45 panic!("arithmetic error!")
46 }
47}
48
49fn do_arith_i(a: LuaValue, b: LuaValue, arith_i: fn(i64, i64) -> i64) -> Option<LuaValue> {
50 let (a, b) = match (a, b) {
51 (LuaValue::Integer(i1), LuaValue::Integer(i2)) => (i1, i2),
52 (LuaValue::Integer(i1), LuaValue::Number(f2)) => (i1, float_to_integer(f2).unwrap()),
53 (LuaValue::Number(f1), LuaValue::Integer(i2)) => (float_to_integer(f1).unwrap(), i2),
54 (LuaValue::Number(f1), LuaValue::Number(f2)) => {
55 (float_to_integer(f1).unwrap(), float_to_integer(f2).unwrap())
56 }
57 (_, _) => return None,
58 };
59 Some(LuaValue::Integer(arith_i(a, b)))
60}
61
62fn do_arith_f(a: LuaValue, b: LuaValue, arith_f: fn(f64, f64) -> f64) -> Option<LuaValue> {
63 let (a, b) = match (a, b) {
64 (LuaValue::Integer(i1), LuaValue::Integer(i2)) => (i1 as f64, i2 as f64),
65 (LuaValue::Integer(i1), LuaValue::Number(f2)) => (i1 as f64, f2),
66 (LuaValue::Number(f1), LuaValue::Integer(i2)) => (f1, i2 as f64),
67 (LuaValue::Number(f1), LuaValue::Number(f2)) => (f1, f2),
68 (_, _) => return None,
69 };
70 Some(LuaValue::Number(arith_f(a, b)))
71}
72
73fn do_arith(
74 a: LuaValue,
75 b: LuaValue,
76 arith_i: fn(i64, i64) -> i64,
77 arith_f: fn(f64, f64) -> f64,
78) -> Option<LuaValue> {
79 match (a, b) {
80 (LuaValue::Integer(i1), LuaValue::Integer(i2)) => Some(LuaValue::Integer(arith_i(i1, i2))),
81 (LuaValue::Integer(i1), LuaValue::Number(f2)) => {
82 Some(LuaValue::Number(arith_f(i1 as f64, f2)))
83 }
84 (LuaValue::Number(f1), LuaValue::Integer(i2)) => {
85 Some(LuaValue::Number(arith_f(f1, i2 as f64)))
86 }
87 (LuaValue::Number(f1), LuaValue::Number(f2)) => Some(LuaValue::Number(arith_f(f1, f2))),
88 (_, _) => None,
89 }
90}