devalang_core/core/preprocessor/resolver/
driver.rs

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