neige_lua/api/
misc.rs

1use std::panic::{catch_unwind, AssertUnwindSafe};
2
3use crate::{api::AccessApi, state::LuaState, value::value::LuaValue};
4
5use super::CallApi;
6
7pub trait MiscApi {
8    fn len(&mut self, idx: isize);
9    fn concat(&mut self, n: usize);
10    fn next(&mut self, idx: isize) -> bool;
11    fn error(&mut self) -> isize;
12    fn pcall(&mut self, n_args: isize, n_results: isize, msg: isize) -> isize;
13}
14
15impl MiscApi for LuaState {
16    fn len(&mut self, idx: isize) {
17        let val = self.stack_get(idx);
18        match val {
19            LuaValue::Str(s) => self.stack_push(LuaValue::Integer(s.len() as i64)),
20            LuaValue::Table(tb) => self.stack_push(LuaValue::Integer(tb.len() as i64)),
21            _ => {
22                let result = self.call_meta_method(val.clone(), val, "__len");
23                if let Some(LuaValue::Integer(i)) = result {
24                    self.stack_push(LuaValue::Integer(i))
25                } else {
26                    panic!("length error!")
27                }
28            }
29        }
30    }
31
32    fn concat(&mut self, n: usize) {
33        if n == 0 {
34            self.stack_push(LuaValue::Str("".into()))
35        } else if n >= 2 {
36            for _ in 1..n {
37                if self.is_string(-1) && self.is_string(-2) {
38                    let s2 = self.to_string(-1);
39                    let s1 = self.to_string(-2);
40                    self.stack_pop();
41                    self.stack_pop();
42                    self.stack_push(LuaValue::Str(format!("{}{}", s1, s2)));
43                    continue;
44                }
45                let b = self.stack_pop();
46                let a = self.stack_pop();
47                let result = self.call_meta_method(a, b, "__concat");
48                if let Some(r) = result {
49                    self.stack_push(r);
50                    continue;
51                }
52                panic!("concatenation error!")
53            }
54        }
55    }
56
57    fn next(&mut self, idx: isize) -> bool {
58        let val = self.stack_get(idx);
59        if let LuaValue::Table(tbl) = val {
60            let key = self.stack_pop();
61            let next_key = tbl.next_key(&key);
62            if !next_key.is_nil() {
63                let next_val = tbl.get(&next_key);
64                self.stack_push(next_key);
65                self.stack_push(next_val);
66                true
67            } else {
68                false
69            }
70        } else {
71            panic!("table expected!")
72        }
73    }
74
75    fn error(&mut self) -> isize {
76        let val = self.stack_pop();
77        panic!("{:?}", val)
78    }
79
80    fn pcall(&mut self, n_args: isize, n_results: isize, msgh: isize) -> isize {
81        let node = self.get_node().clone();
82        let caller = node.get_stack();
83        let mut status = 2;
84
85        let result = catch_unwind(AssertUnwindSafe(|| {
86            self.call(n_args, n_results);
87            status = 0;
88        }));
89        if let Err(err) = result {
90            if msgh != 0 {
91                panic!("{:?}", err);
92            }
93            let stack = node.get_stack();
94            while *stack != *caller {
95                self.pop_lua_stack()
96            }
97            let err_msg = if let Some(err_msg) = err.downcast_ref::<&str>() {
98                err_msg.to_string()
99            } else if let Some(err_msg) = err.downcast_ref::<String>() {
100                err_msg.clone()
101            } else {
102                "Unknown error".to_string()
103            };
104            self.stack_push(LuaValue::Str(err_msg))
105        }
106        status
107    }
108}