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