devalang_core/core/preprocessor/loader/
mod.rs1#[cfg(feature = "cli")]
2use crate::core::preprocessor::resolver::driver::{
3 resolve_all_modules, resolve_and_flatten_all_modules,
4};
5use crate::core::{
7 error::ErrorHandler,
8 lexer::{driver::Lexer, token::Token},
9 parser::{driver::parser::Parser, statement::Statement},
10 preprocessor::{module::Module, processor::handlers::process_modules},
11 store::global::GlobalStore,
12};
13use devalang_utils::path::normalize_path;
14use std::{collections::HashMap, path::Path};
15
16mod inject;
17mod loader_helpers;
18
19pub struct ModuleLoader {
20 pub entry: String,
21 pub output: String,
22 pub base_dir: String,
23}
24
25impl ModuleLoader {
26 pub fn new(entry: &str, output: &str) -> Self {
27 let base_dir = Path::new(entry)
28 .parent()
29 .unwrap_or(Path::new(""))
30 .to_string_lossy()
31 .replace('\\', "/");
32
33 Self {
34 entry: entry.to_string(),
35 output: output.to_string(),
36 base_dir,
37 }
38 }
39
40 pub fn from_raw_source(
41 entry_path: &str,
42 output_path: &str,
43 content: &str,
44 global_store: &mut GlobalStore,
45 ) -> Self {
46 let normalized_entry_path = normalize_path(entry_path);
47
48 let mut module = Module::new(entry_path);
49 module.content = content.to_string();
50
51 global_store.insert_module(normalized_entry_path.to_string(), module);
55
56 Self {
57 entry: normalized_entry_path.to_string(),
58 output: output_path.to_string(),
59 base_dir: "".to_string(),
60 }
61 }
62
63 pub fn extract_statements_map(
64 &self,
65 global_store: &GlobalStore,
66 ) -> HashMap<String, Vec<Statement>> {
67 global_store
68 .modules
69 .iter()
70 .map(|(path, module)| (path.clone(), module.statements.clone()))
71 .collect()
72 }
73
74 pub fn load_single_module(&self, global_store: &mut GlobalStore) -> Result<Module, String> {
75 let mut module = global_store
76 .modules
77 .remove(&self.entry)
78 .ok_or_else(|| format!("Module not found in store for path: {}", self.entry))?;
79
80 let lexer = Lexer::new();
82 let tokens = lexer
83 .lex_from_source(&module.content)
84 .map_err(|e| format!("Lexer failed: {}", e))?;
85
86 module.tokens = tokens.clone();
87
88 let mut parser = Parser::new();
90 parser.set_current_module(self.entry.clone());
91 let statements = parser.parse_tokens(tokens, global_store);
92 module.statements = statements;
93
94 if let Err(e) = inject::inject_bank_triggers(&mut module, "808", None) {
96 return Err(format!("Failed to inject bank triggers: {}", e));
97 }
98
99 for (plugin_name, alias) in inject::extract_plugin_uses(&module.statements) {
100 inject::load_plugin_and_register(&mut module, &plugin_name, &alias, global_store);
101 }
102
103 global_store
104 .modules
105 .insert(self.entry.clone(), module.clone());
106
107 let mut error_handler = ErrorHandler::new();
109 error_handler.detect_from_statements(&mut parser, &module.statements);
110
111 Ok(module)
112 }
113
114 pub fn load_wasm_module(&self, global_store: &mut GlobalStore) -> Result<(), String> {
115 let module = {
117 let module_ref = global_store
118 .modules
119 .get(&self.entry)
120 .ok_or_else(|| format!("❌ Module not found for path: {}", self.entry))?;
121
122 Module::from_existing(&self.entry, module_ref.content.clone())
123 };
124
125 let lexer = Lexer::new();
127 let tokens = lexer
128 .lex_from_source(&module.content)
129 .map_err(|e| format!("Lexer failed: {}", e))?;
130
131 let mut parser = Parser::new();
133 parser.set_current_module(self.entry.clone());
134
135 let statements = parser.parse_tokens(tokens.clone(), global_store);
136
137 let mut updated_module = module;
138 updated_module.tokens = tokens;
139 updated_module.statements = statements;
140
141 if let Err(e) = inject::inject_bank_triggers(&mut updated_module, "808", None) {
143 return Err(format!("Failed to inject bank triggers: {}", e));
144 }
145
146 global_store
150 .modules
151 .insert(self.entry.clone(), updated_module.clone());
152
153 process_modules(self, global_store);
156
157 for (plugin_name, alias) in inject::extract_plugin_uses(&updated_module.statements) {
158 inject::load_plugin_and_register(
159 &mut updated_module,
160 &plugin_name,
161 &alias,
162 global_store,
163 );
164 }
165
166 let mut error_handler = ErrorHandler::new();
168 error_handler.detect_from_statements(&mut parser, &updated_module.statements);
169
170 if let Some(stored_module) = global_store.modules.get(&self.entry) {
176 global_store
177 .variables
178 .variables
179 .extend(stored_module.variable_table.variables.clone());
180 global_store
181 .functions
182 .functions
183 .extend(stored_module.function_table.functions.clone());
184 } else {
185 global_store
188 .variables
189 .variables
190 .extend(updated_module.variable_table.variables.clone());
191 global_store
192 .functions
193 .functions
194 .extend(updated_module.function_table.functions.clone());
195 }
196
197 Ok(())
198 }
199
200 #[cfg(feature = "cli")]
201 pub fn load_all_modules(
202 &self,
203 global_store: &mut GlobalStore,
204 ) -> (HashMap<String, Vec<Token>>, HashMap<String, Vec<Statement>>) {
205 let tokens_by_module = self.load_module_recursively(&self.entry, global_store);
207
208 process_modules(self, global_store);
210 resolve_all_modules(self, global_store);
211
212 let statements_by_module = resolve_and_flatten_all_modules(global_store);
214
215 (tokens_by_module, statements_by_module)
216 }
217
218 #[cfg(feature = "cli")]
219 fn load_module_recursively(
220 &self,
221 raw_path: &str,
222 global_store: &mut GlobalStore,
223 ) -> HashMap<String, Vec<Token>> {
224 crate::core::preprocessor::loader::loader_helpers::load_module_recursively(
225 raw_path,
226 global_store,
227 )
228 }
229
230 #[cfg(feature = "cli")]
231 #[allow(dead_code)]
232 fn load_module_imports(&self, path: &String, global_store: &mut GlobalStore) {
233 crate::core::preprocessor::loader::loader_helpers::load_module_imports(path, global_store)
234 }
235}