devalang_core/core/preprocessor/resolver/
driver.rs

1use crate::core::{
2    parser::statement::{Statement, StatementKind},
3    preprocessor::{
4        loader::ModuleLoader,
5        module::Module,
6        resolver::{
7            bank::resolve_bank, call::resolve_call, condition::resolve_condition,
8            function::resolve_function, group::resolve_group, let_::resolve_let,
9            loop_::resolve_loop, pattern::resolve_pattern, spawn::resolve_spawn,
10            tempo::resolve_tempo, trigger::resolve_trigger,
11        },
12    },
13    store::global::GlobalStore,
14};
15use devalang_types::Value;
16use devalang_utils::logger::LogLevel;
17use devalang_utils::logger::Logger;
18use std::collections::HashMap;
19
20pub fn resolve_all_modules(module_loader: &ModuleLoader, global_store: &mut GlobalStore) {
21    for _module in global_store.clone().modules.values_mut() {
22        resolve_imports(module_loader, global_store);
23    }
24}
25
26pub fn resolve_statement(
27    stmt: &Statement,
28    module: &Module,
29    path: &str,
30    global_store: &mut GlobalStore,
31) -> Statement {
32    match &stmt.kind {
33        StatementKind::On { event, args, body } => {
34            let resolved_body: Vec<Statement> = body
35                .iter()
36                .map(|s| resolve_statement(s, module, path, global_store))
37                .collect();
38            Statement {
39                kind: StatementKind::On {
40                    event: event.clone(),
41                    args: args.clone(),
42                    body: resolved_body,
43                },
44                value: resolve_value(&stmt.value, module, global_store),
45                ..stmt.clone()
46            }
47        }
48        StatementKind::Emit { event, payload: _ } => Statement {
49            kind: StatementKind::Emit {
50                event: event.clone(),
51                payload: Some(resolve_value(&stmt.value, module, global_store)),
52            },
53            value: resolve_value(&stmt.value, module, global_store),
54            ..stmt.clone()
55        },
56        StatementKind::Trigger {
57            entity,
58            duration,
59            effects,
60        } => resolve_trigger(
61            stmt,
62            entity,
63            &mut duration.clone(),
64            effects.clone(),
65            module,
66            path,
67            global_store,
68        ),
69        StatementKind::If => resolve_condition(stmt, module, path, global_store),
70        StatementKind::Group => resolve_group(stmt, module, path, global_store),
71        StatementKind::Pattern { .. } => resolve_pattern(stmt, module, path, global_store),
72        StatementKind::Call { name, args } => {
73            resolve_call(stmt, name.clone(), args.clone(), module, path, global_store)
74        }
75        StatementKind::Spawn { name, args } => {
76            resolve_spawn(stmt, name.clone(), args.clone(), module, path, global_store)
77        }
78        StatementKind::Bank { .. } => resolve_bank(stmt, module, path, global_store),
79        StatementKind::Tempo => resolve_tempo(stmt, module, path, global_store),
80        StatementKind::Loop => resolve_loop(stmt, module, path, global_store),
81        StatementKind::Let { name, .. } => resolve_let(stmt, name, module, path, global_store),
82
83        _ => {
84            let resolved_value = resolve_value(&stmt.value, module, global_store);
85
86            Statement {
87                value: resolved_value,
88                ..stmt.clone()
89            }
90        }
91    }
92}
93
94fn resolve_value(value: &Value, module: &Module, global_store: &mut GlobalStore) -> Value {
95    let logger = Logger::new();
96    match value {
97        Value::Identifier(name) => {
98            if let Some(original_val) = module.variable_table.get(name) {
99                return resolve_value(original_val, module, global_store);
100            }
101
102            if let Some(export_val) = find_export_value(name, global_store) {
103                return resolve_value(&export_val, module, global_store);
104            }
105
106            // Leave unresolved identifiers as-is; they might be runtime-bound (e.g., foreach vars)
107            Value::Identifier(name.clone())
108        }
109
110        Value::String(s) => Value::String(s.clone()),
111
112        Value::Beat(beat_str) => {
113            logger.log_message(
114                LogLevel::Warning,
115                &format!("[warn] '{:?}': unresolved beat '{}'", module.path, beat_str),
116            );
117            Value::Beat(beat_str.clone())
118        }
119
120        Value::Map(map) => {
121            let mut resolved = HashMap::new();
122            for (k, v) in map {
123                resolved.insert(k.clone(), resolve_value(v, module, global_store));
124            }
125            Value::Map(resolved)
126        }
127
128        Value::Block(stmts) => {
129            let resolved_stmts = stmts
130                .iter()
131                .map(|stmt| resolve_statement(stmt, module, &module.path, global_store))
132                .collect();
133            Value::Block(resolved_stmts)
134        }
135
136        other => other.clone(),
137    }
138}
139
140fn find_export_value(name: &str, global_store: &GlobalStore) -> Option<Value> {
141    for module in global_store.modules.values() {
142        if let Some(val) = module.export_table.get_export(name) {
143            return Some(val.clone());
144        }
145    }
146    None
147}
148
149pub fn resolve_imports(_module_loader: &ModuleLoader, global_store: &mut GlobalStore) {
150    let logger = Logger::new();
151    for (module_path, module) in global_store.clone().modules.iter_mut() {
152        for (name, source_path) in &module.import_table.imports {
153            match source_path {
154                Value::String(source_path) => {
155                    if let Some(source_module) = global_store.modules.get(source_path) {
156                        if let Some(value) = source_module.export_table.get_export(name) {
157                            module.variable_table.set(name.clone(), value.clone());
158                        } else {
159                            logger.log_message(LogLevel::Warning, &format!("[warn] '{module_path}': '{name}' not found in exports of '{source_path}'"));
160                        }
161                    } else {
162                        logger.log_message(
163                            LogLevel::Warning,
164                            &format!(
165                                "[warn] '{module_path}': cannot find source module '{source_path}'"
166                            ),
167                        );
168                    }
169                }
170                _ => {
171                    logger.log_message(
172                        LogLevel::Warning,
173                        &format!(
174                            "[warn] '{module_path}': expected string for import source, found {:?}",
175                            source_path
176                        ),
177                    );
178                }
179            }
180        }
181    }
182}
183
184pub fn resolve_and_flatten_all_modules(
185    global_store: &mut GlobalStore,
186) -> HashMap<String, Vec<Statement>> {
187    let logger = Logger::new();
188    let snapshot = global_store.clone();
189
190    // 1. Imports resolution
191    for (module_path, module) in global_store.modules.iter_mut() {
192        for (name, source_path) in &module.import_table.imports {
193            if let Value::String(source_path_str) = source_path {
194                match snapshot.modules.get(source_path_str) {
195                    Some(source_module) => {
196                        if let Some(value) = source_module.export_table.get_export(name) {
197                            module.variable_table.set(name.clone(), value.clone());
198                        } else {
199                            logger.log_error_with_stacktrace(
200                                &format!("'{name}' not found in exports of '{source_path_str}'"),
201                                module_path,
202                            );
203                        }
204                    }
205                    None => {
206                        logger.log_error_with_stacktrace(
207                            &format!("Cannot find source module '{source_path_str}'"),
208                            module_path,
209                        );
210                    }
211                }
212            } else {
213                logger.log_error_with_stacktrace(
214                    &format!("Expected string for import source, found {:?}", source_path),
215                    module_path,
216                );
217            }
218        }
219    }
220
221    // 2. Statements resolution
222    let mut resolved_map: HashMap<String, Vec<Statement>> = HashMap::new();
223    for (path, module) in global_store.modules.clone() {
224        let mut resolved = Vec::new();
225
226        for stmt in &module.statements {
227            let stmt = stmt.clone();
228
229            match &stmt.kind {
230                StatementKind::Let { name } => {
231                    let resolved_stmt = resolve_let(&stmt, name, &module, &path, global_store);
232                    resolved.push(resolved_stmt);
233                }
234
235                StatementKind::Trigger {
236                    entity,
237                    duration,
238                    effects,
239                } => {
240                    let resolved_stmt = resolve_trigger(
241                        &stmt,
242                        entity.as_str(),
243                        &mut duration.clone(),
244                        effects.clone(),
245                        &module,
246                        &path,
247                        global_store,
248                    );
249                    resolved.push(resolved_stmt);
250                }
251
252                StatementKind::Loop => {
253                    let resolved_stmt = resolve_loop(&stmt, &module, &path, global_store);
254                    resolved.push(resolved_stmt);
255                }
256
257                StatementKind::Bank { .. } => {
258                    let resolved_stmt = resolve_bank(&stmt, &module, &path, global_store);
259                    resolved.push(resolved_stmt);
260                }
261
262                StatementKind::Tempo => {
263                    let resolved_stmt = resolve_tempo(&stmt, &module, &path, global_store);
264                    resolved.push(resolved_stmt);
265                }
266
267                StatementKind::Import { .. } | StatementKind::Export { .. } => {
268                    resolved.push(stmt.clone());
269                }
270
271                StatementKind::Call { name, args } => {
272                    let resolved_stmt = resolve_call(
273                        &stmt,
274                        name.clone(),
275                        args.clone(),
276                        &module,
277                        &path,
278                        global_store,
279                    );
280                    resolved.push(resolved_stmt);
281                }
282
283                StatementKind::Spawn { name, args } => {
284                    let resolved_stmt = resolve_spawn(
285                        &stmt,
286                        name.clone(),
287                        args.clone(),
288                        &module,
289                        &path,
290                        global_store,
291                    );
292                    resolved.push(resolved_stmt);
293                }
294
295                StatementKind::Group => {
296                    let resolved_stmt = resolve_group(&stmt, &module, &path, global_store);
297                    resolved.push(resolved_stmt);
298                }
299
300                StatementKind::Pattern { .. } => {
301                    let resolved_stmt = resolve_pattern(&stmt, &module, &path, global_store);
302                    resolved.push(resolved_stmt);
303                }
304
305                StatementKind::Function {
306                    name: _,
307                    parameters: _,
308                    body: _,
309                } => {
310                    let resolved_function = resolve_function(&stmt, &module, &path, global_store);
311                    resolved.push(resolved_function);
312                }
313
314                _ => {
315                    resolved.push(stmt);
316                }
317            }
318        }
319
320        resolved_map.insert(path.clone(), resolved);
321    }
322
323    resolved_map
324}