1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use core::panic;
use std::{any::Any, collections::HashMap, fs, path::PathBuf, rc::Rc};

use crate::{
	data::Data,
	error::Error,
	evaluator, lexer, parser,
	scope::{function::Function, Scope},
	util::{make_ref, MutRc},
};

use super::{
	registry::{ModuleRegistry, RegistryEntry},
	CustomModule, Module,
};

#[derive(Debug)]
pub struct ModuleWrapper(MutRc<dyn Module>);

impl Scope for ModuleWrapper {
	fn has_function(&self, name: &str) -> bool {
		self.0.borrow().has_pub_function(name)
	}

	fn get_function(&self, name: &str) -> Option<Function> {
		self.0.borrow().get_pub_function(name)
	}

	fn set_function(&mut self, _name: &str, _function: Function) {
		panic!("Tried to set function inside external module.")
	}

	fn delete_function(&mut self, _name: &str) {
		panic!("Tried to delete function inside external module.")
	}

	fn set_return_value(&mut self, _value: Data) {}

	fn get_function_list(&self) -> HashMap<String, Function> {
		self.0.borrow().get_function_list()
	}

	fn as_any(&self) -> &dyn Any {
		panic!("INTERNAL! tried to cast ModuleWrapper")
	}
	fn as_mut(&mut self) -> &mut dyn Any {
		self
	}
}

pub fn get(module: &CustomModule, path: String) -> Result<MutRc<ModuleWrapper>, Error> {
	let registry = module.registry.clone();

	if path.starts_with("./") {
		let mut path_buf = module.file_path.clone();
		path_buf.push(path.clone() + ".bean");

		get_local(Rc::clone(&registry), path_buf).map(|m| make_ref(ModuleWrapper(m)))
	} else {
		get_reg(&mut registry.borrow_mut().registered, path.clone()).map_or(
			Err(Error::new(
				&format!("Module {} does not exist.", path),
				None,
			)),
			|s| Ok(make_ref(ModuleWrapper(s))),
		)
	}
}

fn get_reg(
	registered: &mut HashMap<String, RegistryEntry>,
	name: String,
) -> Option<MutRc<dyn Module>> {
	if let Some(RegistryEntry::Uninitialized(_)) = registered.get(&name) {
		let v = registered.remove(&name).unwrap().get_or_init();
		registered.insert(name.clone(), RegistryEntry::Available(v));
	}

	registered.get(&name).map_or(None, |x| match x {
		RegistryEntry::Available(r) => Some(Rc::clone(r)),
		RegistryEntry::Uninitialized(_) => None,
	})
}

fn get_local(
	registry: MutRc<ModuleRegistry>,
	path: PathBuf,
) -> Result<MutRc<CustomModule>, Error> {
	if registry.borrow().loading.contains(&path) {
		return Err(Error::new(
			"Trying to load from a file that is currently being loaded.",
			None,
		));
	}
	let exists = registry.borrow().local.get(&path).is_none();
	if exists {
		let file = fs::read_to_string(path.clone()).map_err(|e| {
			Error::new(
				&(String::from("Error reading file ")
					+ path.to_str().unwrap_or("")
					+ ": " + &e.to_string()),
				None,
			)
		})?;

		let tokens = lexer::tokenize(file);
		let tree = parser::parse(tokens);

		let module = CustomModule::new(Rc::clone(&registry), path.clone());
		let module_ref = make_ref(module);
		registry.borrow_mut().loading.push(path.clone());

		evaluator::evaluate(&tree, CustomModule::to_scope(Rc::clone(&module_ref)));

		let mut registry_mut = registry.borrow_mut();
		registry_mut.local.insert(path.clone(), module_ref);
		registry_mut.loading.pop();
	}

	Ok(Rc::clone(registry.borrow().local.get(&path).unwrap()))
}