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 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 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 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}