neige_lua/api/
arith.rs

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}