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}