bean_script/
modules.rs

1use std::{
2	any::Any, cell::RefCell, collections::HashMap, fmt::Debug, path::PathBuf, rc::Rc,
3};
4
5use crate::{
6	data::Data,
7	error::Error,
8	scope::{block_scope::IfState, function::Function, Scope, ScopeRef},
9	util::{make_ref, MutRc},
10};
11
12use self::registry::{ModuleRegistry, RegistryFeatures};
13
14pub mod bean_std;
15pub mod loader;
16pub mod registry;
17
18pub trait Module: Scope {
19	fn get_submodule(&self, name: &str) -> Option<MutRc<dyn Module>>;
20
21	fn has_pub_function(&self, name: &str) -> bool;
22	fn get_pub_function(&self, name: &str) -> Option<Function>;
23}
24
25pub struct ModuleBuilder {
26	functions: HashMap<
27		String,
28		Rc<dyn Fn(Vec<Data>, Option<Function>, ScopeRef) -> Result<Data, Error>>,
29	>,
30	submodules: HashMap<String, Rc<RefCell<BuiltinModule>>>,
31	features: RegistryFeatures,
32}
33
34impl ModuleBuilder {
35	pub fn function<F>(&mut self, name: &str, function: F) -> &mut Self
36	where
37		F: Fn(Vec<Data>, Option<Function>, ScopeRef) -> Result<Data, Error> + 'static,
38	{
39		self.functions.insert(String::from(name), Rc::new(function));
40		self
41	}
42
43	pub fn submodule<F>(&mut self, name: &str, constructor: F) -> &mut Self
44	where
45		F: FnOnce(&mut ModuleBuilder),
46	{
47		let mut module = ModuleBuilder {
48			functions: HashMap::new(),
49			submodules: HashMap::new(),
50			features: self.features,
51		};
52		constructor(&mut module);
53		self.submodules.insert(
54			String::from(name),
55			Rc::new(RefCell::new(BuiltinModule {
56				functions: module.functions,
57				submodules: module.submodules,
58			})),
59		);
60		self
61	}
62}
63
64#[derive(Clone)]
65pub struct BuiltinModule {
66	functions: HashMap<
67		String,
68		Rc<dyn Fn(Vec<Data>, Option<Function>, ScopeRef) -> Result<Data, Error>>,
69	>,
70	submodules: HashMap<String, Rc<RefCell<BuiltinModule>>>,
71}
72
73impl BuiltinModule {
74	pub fn new(
75		constructor: impl FnOnce(&mut ModuleBuilder),
76		features: RegistryFeatures,
77	) -> Self {
78		let mut module = ModuleBuilder {
79			functions: HashMap::new(),
80			submodules: HashMap::new(),
81			features,
82		};
83		constructor(&mut module);
84		Self {
85			functions: module.functions,
86			submodules: module.submodules,
87		}
88	}
89}
90
91impl Scope for BuiltinModule {
92	fn has_function(&self, name: &str) -> bool {
93		self.functions.contains_key(name)
94	}
95
96	fn get_function(&self, name: &str) -> Option<Function> {
97		self.functions.get(name).map(|x| Function::BuiltIn {
98			callback: Rc::clone(x),
99		})
100	}
101
102	fn set_function(&mut self, _name: &str, _function: Function) {}
103	fn delete_function(&mut self, _name: &str) {}
104	fn set_return_value(&mut self, _value: Data) {
105		panic!("Cannot return from module.")
106	}
107
108	fn get_function_list(&self) -> HashMap<String, Function> {
109		let mut map = HashMap::new();
110		for (k, fun) in &self.functions {
111			map.insert(
112				k.clone(),
113				Function::BuiltIn {
114					callback: Rc::clone(fun),
115				},
116			);
117		}
118		map
119	}
120
121	fn as_any(&self) -> &dyn Any {
122		self
123	}
124	fn as_mut(&mut self) -> &mut dyn Any {
125		self
126	}
127
128	fn set_if_state(&mut self, _state: IfState) {}
129}
130
131impl Debug for BuiltinModule {
132	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133		f.debug_struct("Module")
134			.field("functions", &self.functions.keys())
135			.field("submodules", &self.submodules)
136			.finish()
137	}
138}
139
140impl Module for BuiltinModule {
141	fn get_submodule(&self, name: &str) -> Option<MutRc<dyn Module>> {
142		self.submodules
143			.get(name)
144			.map(|rc| Rc::clone(rc) as MutRc<dyn Module>)
145	}
146
147	fn has_pub_function(&self, name: &str) -> bool {
148		self.has_function(name)
149	}
150
151	fn get_pub_function(&self, name: &str) -> Option<Function> {
152		self.get_function(name)
153	}
154}
155
156#[derive(Debug, Clone)]
157pub struct CustomModule {
158	local_functions: MutRc<HashMap<String, Function>>,
159	pub registry: MutRc<ModuleRegistry>,
160	pub file_path: PathBuf,
161	pub if_state: IfState,
162	pub exported_functions: MutRc<HashMap<String, Function>>,
163	pub submodules: MutRc<HashMap<String, MutRc<CustomModule>>>,
164}
165
166impl CustomModule {
167	pub fn new(registry: MutRc<ModuleRegistry>, file_path: PathBuf) -> Self {
168		Self {
169			local_functions: make_ref(HashMap::new()),
170			registry,
171			file_path,
172			if_state: IfState::Captured,
173			exported_functions: make_ref(HashMap::new()),
174			submodules: make_ref(HashMap::new()),
175		}
176	}
177
178	// courtesy of [stack overflow](https://stackoverflow.com/a/64400756)
179	fn to_scope(it: MutRc<Self>) -> ScopeRef {
180		it
181	}
182}
183
184impl Scope for CustomModule {
185	fn has_function(&self, name: &str) -> bool {
186		self.local_functions.borrow().contains_key(name)
187	}
188
189	fn get_function(&self, name: &str) -> Option<Function> {
190		let binding = RefCell::borrow(&self.local_functions);
191		let function = binding.get(name);
192		function.map(|x| x.clone()).or_else(|| {
193			RefCell::borrow(&self.registry.borrow().runtime()).get_function(name)
194		})
195	}
196
197	fn set_function(&mut self, name: &str, function: Function) {
198		RefCell::borrow_mut(&self.local_functions).insert(String::from(name), function);
199	}
200
201	fn delete_function(&mut self, name: &str) {
202		RefCell::borrow_mut(&self.local_functions).remove(name);
203	}
204
205	fn parent(&self) -> Option<ScopeRef> {
206		None
207	}
208
209	fn set_return_value(&mut self, _v: Data) {
210		panic!("Attempted to return from root scope.");
211	}
212
213	fn get_function_list(&self) -> HashMap<String, Function> {
214		self.exported_functions.borrow().clone()
215	}
216
217	fn get_file_module(&self) -> Option<ScopeRef> {
218		Some(make_ref(self.clone()))
219	}
220
221	fn as_any(&self) -> &dyn Any {
222		self
223	}
224	fn as_mut(&mut self) -> &mut dyn Any {
225		self
226	}
227
228	fn set_if_state(&mut self, state: IfState) {
229		self.if_state = state;
230	}
231
232	fn get_if_state(&self) -> Option<IfState> {
233		Some(self.if_state)
234	}
235}
236
237impl Module for CustomModule {
238	fn get_submodule(&self, name: &str) -> Option<Rc<RefCell<dyn Module>>> {
239		self.submodules
240			.borrow()
241			.get(name)
242			.map(|rc| Rc::clone(rc) as MutRc<dyn Module>)
243	}
244
245	fn has_pub_function(&self, name: &str) -> bool {
246		self.exported_functions.borrow().contains_key(name)
247	}
248
249	fn get_pub_function(&self, name: &str) -> Option<Function> {
250		self.exported_functions.borrow().get(name).cloned()
251	}
252}