Skip to main content

dar_core/
environment.rs

1// crates/dar-core/src/environment.rs
2#![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}