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