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 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}