neige_lua/api/
call.rs

1#[cfg(feature = "wasm")]
2use std::rc::Rc;
3#[cfg(not(feature = "wasm"))]
4use std::{fs::File, io::BufReader, rc::Rc};
5
6use neige_infra::{code::inst::Instruction, LUA_RIDX_GLOBALS};
7use neige_undump::undump;
8
9use crate::{
10    state::{LuaStack, LuaState},
11    value::{closure::Closure, value::LuaValue},
12};
13
14use super::{LuaVm, StackApi};
15
16pub trait CallApi {
17    #[cfg(not(feature = "wasm"))]
18    fn load(&mut self, chunk: BufReader<File>, chunk_name: &str, mode: &str);
19    #[cfg(feature = "wasm")]
20    fn load(&mut self, chunk: Vec<u8>, chunk_name: &str, mode: &str);
21    fn call(&mut self, n_args: isize, n_results: isize);
22}
23
24impl CallApi for LuaState {
25    #[cfg(not(feature = "wasm"))]
26    fn load(&mut self, chunk: BufReader<File>, chunk_name: &str, _mode: &str) {
27        let proto = undump(chunk, chunk_name);
28        let proto_len = proto.upvalues.len();
29        let env = self.registry_get(&LuaValue::Integer(LUA_RIDX_GLOBALS));
30        let c = LuaValue::new_lua_closure(proto);
31        if proto_len > 0 {
32            if let LuaValue::Function(c) = &c {
33                c.upvals.borrow_mut()[0].set_val(env)
34            }
35        }
36        self.stack_push(c);
37    }
38
39    #[cfg(feature = "wasm")]
40    fn load(&mut self, chunk: Vec<u8>, chunk_name: &str, _mode: &str) {
41        use crate::value::value::LuaValue;
42
43        let proto = undump(chunk, chunk_name);
44        let proto_len = proto.upvalues.len();
45        let env = self.registry_get(&LuaValue::Integer(LUA_RIDX_GLOBALS));
46        let c = LuaValue::new_lua_closure(proto);
47        if proto_len > 0 {
48            if let LuaValue::Function(c) = &c {
49                c.upvals.borrow_mut()[0].set_val(env)
50            }
51        }
52        self.stack_push(c);
53    }
54
55    fn call(&mut self, mut n_args: isize, n_results: isize) {
56        let val = self.stack_get(-(n_args + 1));
57        let c = if let LuaValue::Function(c) = val {
58            Some(c)
59        } else {
60            let val = self.inline_get_meta_field(&val, "__call");
61            if let LuaValue::Function(c) = val.clone() {
62                self.stack_push(val);
63                self.insert(-(n_args + 2));
64                n_args += 1;
65                Some(c)
66            } else {
67                None
68            }
69        };
70        if let Some(c) = c {
71            if let Some(_) = &c.proto {
72                self.call_lua_closure(n_args, n_results, c)
73            } else {
74                self.call_rust_closure(n_args, n_results, c)
75            }
76        } else {
77            panic!("not function")
78        }
79    }
80}
81
82impl LuaState {
83    fn call_lua_closure(&mut self, n_args: isize, n_results: isize, c: Rc<Closure>) {
84        let proto = c.proto.clone().unwrap();
85        let n_regs = proto.max_stack_size as usize;
86        let n_params = proto.num_params as isize;
87        let is_var_arg = proto.is_vararg == 1;
88
89        let new_stack = LuaStack::new(n_regs + 20, &self.node, c);
90        {
91            let mut new_stack_mut = new_stack.borrow_mut();
92            let mut func_and_arg = self.stack_pop_n((n_args as usize) + 1);
93            let mut param_or_arg = func_and_arg.split_off(1);
94            param_or_arg.reverse();
95            let len = param_or_arg.len();
96            let un = if n_params < 0 { len } else { n_params as usize };
97            for i in 0..un {
98                if i < len {
99                    new_stack_mut.push(param_or_arg.pop().unwrap());
100                } else {
101                    new_stack_mut.push(LuaValue::Nil)
102                }
103            }
104            new_stack_mut.top = n_regs;
105            if n_args > n_params && is_var_arg {
106                param_or_arg.reverse();
107                new_stack_mut.varargs = param_or_arg
108            }
109        }
110        self.push_lua_stack(new_stack.clone());
111        self.run_lua_closure();
112        self.pop_lua_stack();
113        if n_results != 0 {
114            let mut new_stack_mut = new_stack.borrow_mut();
115            let top = new_stack_mut.top;
116            let results = new_stack_mut.pop_n(top - n_regs);
117            self.check_stack(results.len());
118            self.stack_push_n(results, n_results)
119        }
120    }
121
122    fn run_lua_closure(&mut self) {
123        loop {
124            let inst = self.fetch();
125            self.execute(&inst);
126            if let Instruction::Return(_, _, _) = inst {
127                break;
128            }
129        }
130    }
131
132    fn call_rust_closure(&mut self, n_args: isize, n_results: isize, c: Rc<Closure>) {
133        let rust_fn = c.rust_fn.unwrap();
134
135        let new_stack = LuaStack::new(n_args as usize + 20, &self.node, c);
136        {
137            let mut new_stack_mut = new_stack.borrow_mut();
138            let args = self.stack_pop_n(n_args as usize);
139            new_stack_mut.push_n(args, n_args);
140        }
141        self.stack_pop();
142        self.push_lua_stack(new_stack.clone());
143        let r = rust_fn(self);
144        self.pop_lua_stack();
145        if n_results != 0 {
146            let mut new_stack_mut = new_stack.borrow_mut();
147            let results = new_stack_mut.pop_n(r);
148            self.stack_check(results.len());
149            self.stack_push_n(results, n_results)
150        }
151    }
152}