1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
use std::rc::Rc;

use neige_infra::LuaCompare;

use crate::{state::LuaState, value::value::LuaValue};

pub trait CompareApi {
    fn compare(&mut self, idx1: isize, idx2: isize, op: LuaCompare) -> bool;
    fn raw_equal(&mut self, idx1: isize, idx2: isize) -> bool;
}

impl CompareApi for LuaState {
    fn compare(&mut self, idx1: isize, idx2: isize, op: LuaCompare) -> bool {
        let a = self.stack_get(idx1);
        let b = self.stack_get(idx2);
        match op {
            LuaCompare::Eq => self.eq(a, b, false),
            LuaCompare::Lt => self.lt(a, b),
            LuaCompare::Le => self.le(a, b),
        }
    }

    fn raw_equal(&mut self, idx1: isize, idx2: isize) -> bool {
        if !self.stack_is_valid(idx1) || self.stack_is_valid(idx2) {
            false
        } else {
            let a = self.stack_get(idx1);
            let b = self.stack_get(idx2);
            self.eq(a, b, true)
        }
    }
}

impl LuaState {
    fn eq(&mut self, a: LuaValue, b: LuaValue, raw: bool) -> bool {
        match (a, b) {
            (LuaValue::Nil, LuaValue::Nil) => return true,
            (LuaValue::Boolean(x), LuaValue::Boolean(y)) => x == y,
            (LuaValue::Integer(x), LuaValue::Integer(y)) => x == y,
            (LuaValue::Integer(x), LuaValue::Number(y)) => x as f64 == y,
            (LuaValue::Number(x), LuaValue::Integer(y)) => x == y as f64,
            (LuaValue::Number(x), LuaValue::Number(y)) => x == y,
            (LuaValue::Str(x), LuaValue::Str(y)) => x == y,
            (a, b) => {
                if !raw {
                    let mt = self.call_meta_method(a.clone(), b.clone(), "__eq");
                    if let Some(mt) = mt {
                        return mt.convert_to_boolean();
                    }
                }
                if let LuaValue::Table(x) = &a {
                    if let LuaValue::Table(y) = &b {
                        return Rc::ptr_eq(x, y);
                    }
                }
                panic!("comparsion error!")
            }
        }
    }

    fn lt(&mut self, a: LuaValue, b: LuaValue) -> bool {
        match (a, b) {
            (LuaValue::Integer(x), LuaValue::Integer(y)) => x < y,
            (LuaValue::Integer(x), LuaValue::Number(y)) => (x as f64) < y,
            (LuaValue::Number(x), LuaValue::Integer(y)) => x < (y as f64),
            (LuaValue::Number(x), LuaValue::Number(y)) => x < y,
            (LuaValue::Str(x), LuaValue::Str(y)) => x < y,
            (a, b) => {
                let mt = self.call_meta_method(a, b, "__lt");
                if let Some(mt) = mt {
                    return mt.convert_to_boolean();
                }

                panic!("comparsion error!")
            }
        }
    }

    fn le(&mut self, a: LuaValue, b: LuaValue) -> bool {
        match (a, b) {
            (LuaValue::Integer(x), LuaValue::Integer(y)) => x <= y,
            (LuaValue::Integer(x), LuaValue::Number(y)) => (x as f64) <= y,
            (LuaValue::Number(x), LuaValue::Integer(y)) => x <= (y as f64),
            (LuaValue::Number(x), LuaValue::Number(y)) => x <= y,
            (LuaValue::Str(x), LuaValue::Str(y)) => x <= y,
            (a, b) => {
                let mt = self.call_meta_method(a.clone(), b.clone(), "__le");
                if let Some(mt) = mt {
                    return mt.convert_to_boolean();
                }
                let mt = self.call_meta_method(b, a, "__lt");
                if let Some(mt) = mt {
                    return mt.convert_to_boolean();
                }
                panic!("comparsion error!");
            }
        }
    }
}