1#![allow(clippy::arc_with_non_send_sync)]
3use std::{collections::HashMap, sync::Arc};
4
5use libloading::Library;
6use mlua::Lua;
7
8use crate::{
9 ast::ExternalFunc,
10 value::{Text, Value},
11};
12pub struct Environment {
13 pub variables: HashMap<String, Value,>,
14 functions: HashMap<String, Value,>,
15 libraries: HashMap<String, Arc<Library,>,>,
16 lua_states: HashMap<String, Arc<Lua,>,>,
17}
18impl Environment {
19 pub fn new() -> Self {
20 Self {
21 variables: HashMap::new(),
22 functions: HashMap::new(),
23 libraries: HashMap::new(),
24 lua_states: HashMap::new(),
25 }
26 }
27 pub fn declare_var(
28 &mut self,
29 name: &str,
30 value: Value,
31 ) -> Result<(), String,> {
32 if self.variables.contains_key(name,) {
33 return Err(format!("Variable {} already declared", name),);
34 }
35 self.variables.insert(name.to_string(), value,);
36 Ok((),)
37 }
38 pub fn get_var(&self, name: &str,) -> Result<&Value, String,> {
39 self.variables
40 .get(name,)
41 .ok_or_else(|| format!("Undefined variable: {}", name),)
42 }
43 pub fn has_var(&self, name: &str,) -> bool {
44 self.variables.contains_key(name,)
45 }
46 pub fn declare_function(
47 &mut self,
48 name: &str,
49 func: Value,
50 ) -> Result<(), String,> {
51 if self.functions.contains_key(name,) {
52 return Err(format!("Function {} already declared", name),);
53 }
54 self.functions.insert(name.to_string(), func,);
55 Ok((),)
56 }
57 pub fn get_function(&self, name: &str,) -> Result<&Value, String,> {
58 self.functions
59 .get(name,)
60 .ok_or_else(|| format!("Undefined function: {}", name),)
61 }
62 pub fn load_lua_script(
63 &mut self,
64 path: &str,
65 ) -> Result<Arc<Lua,>, String,> {
66 if let Some(state,) = self.lua_states.get(path,) {
67 return Ok(state.clone(),);
68 }
69 let lua = Arc::new(Lua::new(),);
70 let script = std::fs::read_to_string(path,).map_err(|e| {
71 format!("Failed to read Lua script '{}': {}", path, e)
72 },)?;
73 lua.load(&script,)
74 .exec()
75 .map_err(|e| format!("Lua execution error: {}", e),)?;
76 self.lua_states.insert(path.to_string(), lua.clone(),);
77 Ok(lua,)
78 }
79 pub fn register_lua_function(
80 &mut self,
81 dar_name: &str,
82 lua_func_name: &str,
83 lua_state: Arc<Lua,>,
84 ) -> Result<(), String,> {
85 let func_name = lua_func_name.to_string();
86 let adapter = move |text: Text| {
87 let rust_str = text.to_rust_string();
88 let globals = lua_state.globals();
89 match globals.get::<_, mlua::Function>(func_name.as_str(),) {
90 Ok(lua_func,) => {
91 match lua_func.call::<_, mlua::Value>(rust_str,) {
92 Ok(result,) => {
93 if let Some(lua_str,) = result.as_string()
94 && let Ok(s,) = lua_str.to_str()
95 {
96 return Text::Value(s.to_string(),);
97 }
98 Text::Empty
99 },
100 Err(e,) => {
101 eprintln!("Lua error in '{}': {}", func_name, e);
102 Text::Empty
103 },
104 }
105 },
106 Err(e,) => {
107 eprintln!("Lua function '{}' not found: {}", func_name, e);
108 Text::Empty
109 },
110 }
111 };
112 self.declare_function(
113 dar_name,
114 Value::NativeFunction(Arc::new(adapter,),),
115 )?;
116 Ok((),)
117 }
118 pub fn register_external_functions(
119 &mut self,
120 lib_path: &str,
121 funcs: &[ExternalFunc],
122 ) -> Result<(), String,> {
123 unsafe {
124 let lib_arc = if let Some(lib,) = self.libraries.get(lib_path,) {
125 lib.clone()
126 } else {
127 let lib = Library::new(lib_path,).map_err(|e| {
128 format!("Failed to load library '{}': {}", lib_path, e)
129 },)?;
130 let lib_arc = Arc::new(lib,);
131 self.libraries.insert(lib_path.to_string(), lib_arc.clone(),);
132 lib_arc
133 };
134 for func in funcs {
135 let sym: libloading::Symbol<
136 unsafe extern "C" fn(*const u8, usize,),
137 > = lib_arc.get(func.source_name.as_bytes(),).map_err(
138 |_| {
139 format!(
140 "Symbol '{}' not found in '{}'",
141 func.source_name, lib_path
142 )
143 },
144 )?;
145 let func_ptr = *sym;
146 let adapter = move |text: Text| {
147 let rust_str = text.to_rust_string();
148 func_ptr(rust_str.as_ptr(), rust_str.len(),);
149 Text::Empty
150 };
151 let lang_name =
152 func.alias.as_ref().unwrap_or(&func.source_name,);
153 self.declare_function(
154 lang_name,
155 Value::NativeFunction(Arc::new(adapter,),),
156 )?;
157 }
158 Ok((),)
159 }
160 }
161}
162impl Default for Environment {
163 fn default() -> Self {
164 Self::new()
165 }
166}