devalang_core/core/preprocessor/resolver/
driver.rs

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