1use std::collections::HashMap;
10use std::sync::Arc;
11
12use super::compiler::Compiler;
13use super::parser::Parser;
14use super::stdlib;
15use super::vm::{NativeFunc, ScriptError, Table, Value, Vm};
16
17pub type HostFunction =
21 Arc<dyn Fn(&mut Vm, Vec<Value>) -> Result<Vec<Value>, ScriptError> + Send + Sync>;
22
23pub struct ScriptHost {
27 vm: Vm,
28 modules: HashMap<String, Value>,
29}
30
31impl ScriptHost {
32 pub fn new() -> Self {
34 let mut vm = Vm::new();
35 stdlib::register_all(&mut vm);
36 ScriptHost { vm, modules: HashMap::new() }
37 }
38
39 pub fn sandboxed() -> Self {
41 ScriptHost { vm: Vm::new(), modules: HashMap::new() }
42 }
43
44 pub fn register<F>(&mut self, name: &str, f: F)
48 where
49 F: Fn(&mut Vm, Vec<Value>) -> Result<Vec<Value>, ScriptError> + Send + Sync + 'static,
50 {
51 self.vm.register_native(name, f);
52 }
53
54 pub fn register_fn<F>(&mut self, name: &str, f: F)
56 where
57 F: Fn(Vec<Value>) -> Result<Vec<Value>, ScriptError> + Send + Sync + 'static,
58 {
59 let f = Arc::new(f);
60 self.vm.register_native(name, move |_vm, args| f(args));
61 }
62
63 pub fn set(&mut self, name: &str, value: Value) {
65 self.vm.set_global(name, value);
66 }
67
68 pub fn get(&self, name: &str) -> Value {
70 self.vm.get_global(name)
71 }
72
73 pub fn register_module(&mut self, name: &str, funcs: Vec<(&str, HostFunction)>) {
81 let table = Table::new();
82 for (fname, f) in funcs {
83 let fname = fname.to_string();
84 let func_arc = Arc::clone(&f);
85 table.rawset_str(&fname, Value::NativeFunction(Arc::new(NativeFunc {
86 name: format!("{}.{}", name, fname),
87 func: Box::new(move |vm, args| (func_arc)(vm, args)),
88 })));
89 }
90 let v = Value::Table(table.clone());
91 self.vm.set_global(name, v.clone());
92 self.modules.insert(name.to_string(), v);
93 }
94
95 pub fn exec(&mut self, source: &str) -> Result<Vec<Value>, ScriptError> {
99 let script = Parser::from_source("<inline>", source)
100 .map_err(|e| ScriptError::new(e.to_string()))?;
101 let chunk = Compiler::compile_script(&script);
102 self.vm.execute(chunk)
103 }
104
105 pub fn exec_named(&mut self, name: &str, source: &str) -> Result<Vec<Value>, ScriptError> {
107 let script = Parser::from_source(name, source)
108 .map_err(|e| ScriptError::new(e.to_string()))?;
109 let chunk = Compiler::compile_script(&script);
110 self.vm.execute(chunk)
111 }
112
113 pub fn call(&mut self, func_name: &str, args: Vec<Value>) -> Result<Vec<Value>, ScriptError> {
115 let func = self.vm.get_global(func_name);
116 self.vm.call(func, args)
117 }
118
119 pub fn call_method(
121 &mut self,
122 table_name: &str,
123 method_name: &str,
124 args: Vec<Value>,
125 ) -> Result<Vec<Value>, ScriptError> {
126 let table = self.vm.get_global(table_name);
127 match &table {
128 Value::Table(t) => {
129 let method = t.rawget_str(method_name);
130 self.vm.call(method, args)
131 }
132 other => Err(ScriptError::new(format!(
133 "call_method: {} is not a table (got {})", table_name, other.type_name()
134 ))),
135 }
136 }
137
138 pub fn get_int(&self, name: &str) -> Option<i64> {
142 self.vm.get_global(name).to_int()
143 }
144
145 pub fn get_float(&self, name: &str) -> Option<f64> {
147 self.vm.get_global(name).to_float()
148 }
149
150 pub fn get_string(&self, name: &str) -> Option<String> {
152 self.vm.get_global(name).to_str_repr()
153 }
154
155 pub fn get_bool(&self, name: &str) -> Option<bool> {
157 match self.vm.get_global(name) {
158 Value::Bool(b) => Some(b),
159 _ => None,
160 }
161 }
162
163 pub fn drain_output(&mut self) -> Vec<String> {
167 std::mem::take(&mut self.vm.output)
168 }
169
170 pub fn vm(&mut self) -> &mut Vm {
172 &mut self.vm
173 }
174}
175
176impl Default for ScriptHost {
177 fn default() -> Self {
178 ScriptHost::new()
179 }
180}
181
182pub struct EventBus {
186 handlers: HashMap<String, Vec<String>>, }
188
189impl EventBus {
190 pub fn new() -> Self {
191 EventBus { handlers: HashMap::new() }
192 }
193
194 pub fn on(&mut self, event: &str, func_name: &str) {
196 self.handlers
197 .entry(event.to_string())
198 .or_default()
199 .push(func_name.to_string());
200 }
201
202 pub fn emit(
204 &self,
205 event: &str,
206 host: &mut ScriptHost,
207 args: Vec<Value>,
208 ) -> Result<(), ScriptError> {
209 if let Some(handlers) = self.handlers.get(event) {
210 for func_name in handlers {
211 host.call(func_name, args.clone())?;
212 }
213 }
214 Ok(())
215 }
216
217 pub fn clear(&mut self, event: &str) {
219 self.handlers.remove(event);
220 }
221}
222
223pub trait ScriptObject: Send + Sync {
227 fn script_type_name(&self) -> &'static str;
228 fn get_field(&self, name: &str) -> Value;
229 fn set_field(&mut self, name: &str, value: Value);
230 fn call_method(&mut self, name: &str, args: Vec<Value>) -> Result<Vec<Value>, ScriptError>;
231}
232
233pub fn object_to_table<O: ScriptObject>(obj: &O) -> Table {
236 let t = Table::new();
237 t.rawset_str("__type", Value::Str(Arc::new(obj.script_type_name().to_string())));
239 t
240}
241
242pub struct ScriptComponent {
246 source: String,
247 globals: Table,
248}
249
250impl ScriptComponent {
251 pub fn new(source: impl Into<String>) -> Self {
252 ScriptComponent {
253 source: source.into(),
254 globals: Table::new(),
255 }
256 }
257
258 pub fn init(&mut self, host: &mut ScriptHost) -> Result<(), ScriptError> {
260 host.set("self", Value::Table(self.globals.clone()));
262 host.exec_named("<component>", &self.source)?;
263 Ok(())
264 }
265
266 pub fn call(&mut self, host: &mut ScriptHost, method: &str, args: Vec<Value>) -> Result<Vec<Value>, ScriptError> {
268 let func = self.globals.rawget_str(method);
269 if matches!(func, Value::Nil) {
270 return Ok(vec![]);
271 }
272 host.vm().call(func, args)
273 }
274
275 pub fn table(&self) -> &Table { &self.globals }
276}
277
278#[cfg(test)]
281mod tests {
282 use super::*;
283
284 #[test]
285 fn test_host_exec() {
286 let mut host = ScriptHost::new();
287 let result = host.exec("return 1 + 2").unwrap();
288 assert_eq!(result[0], Value::Int(3));
289 }
290
291 #[test]
292 fn test_host_set_get() {
293 let mut host = ScriptHost::new();
294 host.set("x", Value::Int(99));
295 let result = host.exec("return x").unwrap();
296 assert_eq!(result[0], Value::Int(99));
297 }
298
299 #[test]
300 fn test_host_register_fn() {
301 let mut host = ScriptHost::new();
302 host.register("double", |_vm, args| {
303 let n = args.first().and_then(|v| v.to_int()).unwrap_or(0);
304 Ok(vec![Value::Int(n * 2)])
305 });
306 let result = host.exec("return double(21)").unwrap();
307 assert_eq!(result[0], Value::Int(42));
308 }
309
310 #[test]
311 fn test_host_call_function() {
312 let mut host = ScriptHost::new();
313 host.exec("function greet(name) return \"Hello, \" .. name end").unwrap();
314 let result = host.call("greet", vec![Value::Str(Arc::new("World".to_string()))]).unwrap();
315 assert!(matches!(&result[0], Value::Str(s) if s.as_ref() == "Hello, World"));
316 }
317
318 #[test]
319 fn test_host_print_capture() {
320 let mut host = ScriptHost::new();
321 host.exec("print(\"hello\")").unwrap();
322 let out = host.drain_output();
323 assert_eq!(out, vec!["hello"]);
324 }
325
326 #[test]
327 fn test_event_bus() {
328 let mut host = ScriptHost::new();
329 let mut bus = EventBus::new();
330 host.exec("function on_tick() end").unwrap();
331 bus.on("tick", "on_tick");
332 assert!(bus.emit("tick", &mut host, vec![]).is_ok());
333 }
334
335 #[test]
336 fn test_register_module() {
337 let mut host = ScriptHost::new();
338 let add_fn: HostFunction = Arc::new(|_vm, args| {
339 let a = args.first().and_then(|v| v.to_int()).unwrap_or(0);
340 let b = args.get(1).and_then(|v| v.to_int()).unwrap_or(0);
341 Ok(vec![Value::Int(a + b)])
342 });
343 host.register_module("mymod", vec![("add", add_fn)]);
344 let result = host.exec("return mymod.add(3, 4)").unwrap();
345 assert_eq!(result[0], Value::Int(7));
346 }
347
348 #[test]
349 fn test_sandboxed_no_stdlib() {
350 let mut host = ScriptHost::sandboxed();
351 let result = host.exec("return type(math)");
353 match result {
355 Ok(r) => assert!(matches!(&r[0], Value::Str(s) if s.as_ref() == "nil")),
356 Err(_) => {} }
358 }
359}