bean_script/modules/
loader.rs1use core::panic;
2use std::{any::Any, collections::HashMap, fs, path::PathBuf, rc::Rc};
3
4use crate::{
5 data::Data,
6 error::{BeanResult, Error, ErrorSource},
7 evaluator, lexer, parser,
8 scope::{function::Function, Scope},
9 util::{make_ref, MutRc},
10};
11
12use super::{
13 registry::{ModuleRegistry, RegistryEntry},
14 CustomModule, Module,
15};
16
17#[derive(Debug)]
18pub struct ModuleWrapper(MutRc<dyn Module>);
19
20impl Scope for ModuleWrapper {
21 fn has_function(&self, name: &str) -> bool {
22 self.0.borrow().has_pub_function(name)
23 }
24
25 fn get_function(&self, name: &str) -> Option<Function> {
26 self.0.borrow().get_pub_function(name)
27 }
28
29 fn set_function(&mut self, _name: &str, _function: Function) {
30 panic!("Tried to set function inside external module.")
31 }
32
33 fn delete_function(&mut self, _name: &str) {
34 panic!("Tried to delete function inside external module.")
35 }
36
37 fn set_return_value(&mut self, _value: Data) {}
38
39 fn get_function_list(&self) -> HashMap<String, Function> {
40 self.0.borrow().get_function_list()
41 }
42
43 fn as_any(&self) -> &dyn Any {
44 self
45 }
46 fn as_mut(&mut self) -> &mut dyn Any {
47 self
48 }
49
50 fn set_if_state(&mut self, _state: crate::scope::block_scope::IfState) {}
51}
52
53pub fn get(module: &CustomModule, path: String) -> Result<MutRc<ModuleWrapper>, Error> {
54 let registry = module.registry.clone();
55
56 if path.starts_with("./") {
57 let mut path_buf = module.file_path.clone();
58 path_buf.push(path.clone().trim_start_matches("./"));
59 path_buf.set_extension("bean");
60
61 get_local(Rc::clone(®istry), path_buf).map(|m| make_ref(ModuleWrapper(m)))
62 } else {
63 get_reg(&mut registry.borrow_mut().registered, path.clone()).map_or(
64 Err(Error::new(
65 &format!("Module {} does not exist.", path),
66 ErrorSource::Internal,
67 )),
68 |s| Ok(make_ref(ModuleWrapper(s))),
69 )
70 }
71}
72
73fn get_reg(
74 registered: &mut HashMap<String, RegistryEntry>,
75 name: String,
76) -> Option<MutRc<dyn Module>> {
77 if let Some(RegistryEntry::Uninitialized(_)) = registered.get(&name) {
78 let v = registered.remove(&name).unwrap().get_or_init();
79 registered.insert(name.clone(), RegistryEntry::Available(v));
80 }
81
82 registered.get(&name).map_or(None, |x| match x {
83 RegistryEntry::Available(r) => Some(Rc::clone(r)),
84 RegistryEntry::Uninitialized(_) => None,
85 })
86}
87
88fn get_local(
89 registry: MutRc<ModuleRegistry>,
90 path: PathBuf,
91) -> Result<MutRc<CustomModule>, Error> {
92 if !registry.borrow().features.custom_modules {
93 return Err(Error::new(
94 "Cannot load custom files.",
95 ErrorSource::Internal,
96 ));
97 }
98
99 if registry.borrow().loading.contains(&path) {
100 return Err(Error::new(
101 "Trying to load from a file that is currently being loaded.",
102 ErrorSource::Internal,
103 ));
104 }
105 let exists = registry.borrow().local.get(&path).is_none();
106 if exists {
107 let file = fs::read_to_string(path.clone()).map_err(|e| {
108 Error::new(
109 &(String::from("Error reading file ")
110 + path.to_str().unwrap_or("")
111 + ": " + &e.to_string()),
112 ErrorSource::Internal,
113 )
114 })?;
115
116 let tokens = lexer::tokenize(file);
117 let tree = parser::parse(tokens)?;
118
119 let module = CustomModule::new(Rc::clone(®istry), path.clone());
120 let module_ref = make_ref(module);
121 registry.borrow_mut().loading.push(path.clone());
122
123 evaluator::evaluate(&tree, CustomModule::to_scope(Rc::clone(&module_ref)))
124 .trace(ErrorSource::File(path.to_str().unwrap().to_string()))?;
125
126 let mut registry_mut = registry.borrow_mut();
127 registry_mut.local.insert(path.clone(), module_ref);
128 registry_mut.loading.pop();
129 }
130
131 Ok(Rc::clone(registry.borrow().local.get(&path).unwrap()))
132}