bean_script/modules/
loader.rs

1use 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(&registry), 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(&registry), 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}