@devaloop/devalang 0.0.1-alpha.12 → 0.0.1-alpha.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/Cargo.toml +54 -53
  2. package/README.md +1 -14
  3. package/docs/CHANGELOG.md +26 -0
  4. package/docs/TODO.md +1 -1
  5. package/examples/index.deva +10 -13
  6. package/out-tsc/bin/devalang.exe +0 -0
  7. package/package.json +1 -1
  8. package/project-version.json +3 -3
  9. package/rust/cli/build.rs +25 -2
  10. package/rust/cli/check.rs +26 -3
  11. package/rust/cli/play.rs +1 -1
  12. package/rust/core/audio/engine.rs +126 -73
  13. package/rust/core/audio/interpreter/call.rs +72 -47
  14. package/rust/core/audio/interpreter/condition.rs +14 -12
  15. package/rust/core/audio/interpreter/driver.rs +84 -127
  16. package/rust/core/audio/interpreter/function.rs +21 -0
  17. package/rust/core/audio/interpreter/load.rs +1 -1
  18. package/rust/core/audio/interpreter/loop_.rs +24 -18
  19. package/rust/core/audio/interpreter/mod.rs +2 -1
  20. package/rust/core/audio/interpreter/sleep.rs +0 -6
  21. package/rust/core/audio/interpreter/spawn.rs +78 -60
  22. package/rust/core/audio/interpreter/trigger.rs +157 -70
  23. package/rust/core/audio/loader/trigger.rs +37 -4
  24. package/rust/core/audio/player.rs +20 -10
  25. package/rust/core/audio/renderer.rs +24 -25
  26. package/rust/core/debugger/mod.rs +2 -0
  27. package/rust/core/debugger/module.rs +47 -0
  28. package/rust/core/debugger/store.rs +25 -11
  29. package/rust/core/error/mod.rs +6 -0
  30. package/rust/core/lexer/handler/driver.rs +23 -1
  31. package/rust/core/lexer/handler/identifier.rs +1 -0
  32. package/rust/core/lexer/handler/mod.rs +1 -0
  33. package/rust/core/lexer/handler/parenthesis.rs +41 -0
  34. package/rust/core/lexer/token.rs +3 -0
  35. package/rust/core/parser/driver.rs +3 -1
  36. package/rust/core/parser/handler/dot.rs +64 -127
  37. package/rust/core/parser/handler/identifier/call.rs +69 -22
  38. package/rust/core/parser/handler/identifier/function.rs +92 -0
  39. package/rust/core/parser/handler/identifier/let_.rs +13 -19
  40. package/rust/core/parser/handler/identifier/mod.rs +1 -0
  41. package/rust/core/parser/handler/identifier/spawn.rs +74 -27
  42. package/rust/core/parser/statement.rs +16 -4
  43. package/rust/core/preprocessor/loader.rs +45 -29
  44. package/rust/core/preprocessor/module.rs +3 -1
  45. package/rust/core/preprocessor/processor.rs +26 -1
  46. package/rust/core/preprocessor/resolver/call.rs +61 -84
  47. package/rust/core/preprocessor/resolver/condition.rs +11 -6
  48. package/rust/core/preprocessor/resolver/driver.rs +52 -6
  49. package/rust/core/preprocessor/resolver/function.rs +78 -0
  50. package/rust/core/preprocessor/resolver/group.rs +43 -13
  51. package/rust/core/preprocessor/resolver/let_.rs +7 -10
  52. package/rust/core/preprocessor/resolver/mod.rs +2 -1
  53. package/rust/core/preprocessor/resolver/spawn.rs +64 -30
  54. package/rust/core/preprocessor/resolver/trigger.rs +7 -3
  55. package/rust/core/preprocessor/resolver/value.rs +10 -1
  56. package/rust/core/shared/value.rs +4 -1
  57. package/rust/core/store/function.rs +34 -0
  58. package/rust/core/store/global.rs +9 -10
  59. package/rust/core/store/mod.rs +2 -1
  60. package/rust/core/store/variable.rs +6 -0
  61. package/rust/lib.rs +10 -7
  62. package/rust/utils/mod.rs +45 -1
@@ -49,6 +49,11 @@ pub enum StatementKind {
49
49
  method: String,
50
50
  args: Vec<Value>,
51
51
  },
52
+ Function {
53
+ name: String,
54
+ parameters: Vec<String>,
55
+ body: Vec<Statement>,
56
+ },
52
57
 
53
58
  // ───── Instruments ─────
54
59
  Synth,
@@ -57,12 +62,19 @@ pub enum StatementKind {
57
62
  Trigger {
58
63
  entity: String,
59
64
  duration: Duration,
65
+ effects: Option<Value>,
60
66
  },
61
67
  Sleep,
62
- Call,
63
- Spawn,
68
+ Call {
69
+ name: String,
70
+ args: Vec<Value>,
71
+ },
72
+ Spawn {
73
+ name: String,
74
+ args: Vec<Value>,
75
+ },
64
76
  Loop,
65
-
77
+
66
78
  // ───── Structure & Logic ─────
67
79
  Group,
68
80
 
@@ -93,4 +105,4 @@ pub enum StatementKind {
93
105
  Error {
94
106
  message: String,
95
107
  },
96
- }
108
+ }
@@ -127,6 +127,11 @@ impl ModuleLoader {
127
127
  updated_module.tokens = tokens;
128
128
  updated_module.statements = statements;
129
129
 
130
+ // Step four : Injecting bank triggers if any
131
+ if let Err(e) = self.inject_bank_triggers(&mut updated_module, "808") {
132
+ return Err(format!("Failed to inject bank triggers: {}", e));
133
+ }
134
+
130
135
  // Step four : error handling
131
136
  let mut error_handler = ErrorHandler::new();
132
137
  error_handler.detect_from_statements(&mut parser, &updated_module.statements);
@@ -143,16 +148,16 @@ impl ModuleLoader {
143
148
  global_store: &mut GlobalStore
144
149
  ) -> (HashMap<String, Vec<Token>>, HashMap<String, Vec<Statement>>) {
145
150
  // SECTION Load the entry module and its dependencies
146
-
147
151
  let tokens_by_module = self.load_module_recursively(&self.entry, global_store);
148
152
 
149
153
  // SECTION Process and resolve modules
150
154
  process_modules(self, global_store);
151
155
  resolve_all_modules(self, global_store);
152
156
 
153
- let statemnts_by_module = resolve_and_flatten_all_modules(global_store);
157
+ // SECTION Flatten all modules to get statements (+ injects)
158
+ let statements_by_module = resolve_and_flatten_all_modules(global_store);
154
159
 
155
- (tokens_by_module, statemnts_by_module)
160
+ (tokens_by_module, statements_by_module)
156
161
  }
157
162
 
158
163
  #[cfg(feature = "cli")]
@@ -182,12 +187,15 @@ impl ModuleLoader {
182
187
  module.statements = statements.clone();
183
188
 
184
189
  // Inject triggers for each bank used in module
185
- for bank_name in ModuleLoader::extract_bank_names(&statements) {
186
- if let Err(e) = self.inject_bank_triggers(&mut module, &bank_name) {
187
- return HashMap::new(); // Return empty map on error
188
- }
190
+ for bank_name in self.extract_bank_names(&statements) {
191
+ self.inject_bank_triggers(&mut module, &bank_name);
189
192
  }
190
193
 
194
+ // Inject module variables and functions into global store
195
+ global_store.variables.variables.extend(module.variable_table.variables.clone());
196
+ global_store.functions.functions.extend(module.function_table.functions.clone());
197
+
198
+ // Inject the module into the global store
191
199
  global_store.insert_module(path.clone(), module);
192
200
 
193
201
  // Load dependencies
@@ -241,25 +249,29 @@ impl ModuleLoader {
241
249
  }
242
250
  }
243
251
 
244
- pub fn inject_bank_triggers(&self, module: &mut Module, bank_name: &str) -> Result<(), String> {
252
+ pub fn inject_bank_triggers(
253
+ &self,
254
+ module: &mut Module,
255
+ bank_name: &str
256
+ ) -> Result<Module, String> {
245
257
  let bank_path = Path::new("./.deva/bank").join(bank_name);
246
- let bank_file_path = bank_path.join("bank.toml");
258
+ let bank_toml_path = bank_path.join("bank.toml");
247
259
 
248
- if !bank_file_path.exists() {
249
- return Ok(()); // Pas d'erreur si la banque n'existe pas encore
260
+ if !bank_toml_path.exists() {
261
+ return Ok(module.clone());
250
262
  }
251
263
 
252
264
  let content = std::fs
253
- ::read_to_string(&bank_file_path)
254
- .map_err(|e| format!("Failed to read '{}': {}", bank_file_path.display(), e))?;
265
+ ::read_to_string(&bank_toml_path)
266
+ .map_err(|e| format!("Failed to read '{}': {}", bank_toml_path.display(), e))?;
255
267
 
256
- let parsed: BankFile = toml
268
+ let parsed_bankfile: BankFile = toml
257
269
  ::from_str(&content)
258
- .map_err(|e| format!("Failed to parse '{}': {}", bank_file_path.display(), e))?;
270
+ .map_err(|e| format!("Failed to parse '{}': {}", bank_toml_path.display(), e))?;
259
271
 
260
272
  let mut bank_map = HashMap::new();
261
273
 
262
- for bank_trigger in parsed.triggers.unwrap_or_default() {
274
+ for bank_trigger in parsed_bankfile.triggers.unwrap_or_default() {
263
275
  let trigger_name = bank_trigger.name.clone().replace("./", "");
264
276
  let bank_trigger_path = format!("devalang://bank/{}/{}", bank_name, trigger_name);
265
277
 
@@ -268,7 +280,8 @@ impl ModuleLoader {
268
280
  if module.variable_table.variables.contains_key(bank_name) {
269
281
  eprintln!(
270
282
  "⚠️ Trigger '{}' already defined in module '{}', skipping injection.",
271
- bank_name, module.path
283
+ bank_name,
284
+ module.path
272
285
  );
273
286
  continue;
274
287
  }
@@ -282,24 +295,27 @@ impl ModuleLoader {
282
295
  // Inject the map under the bank name
283
296
  module.variable_table.set(bank_name.to_string(), Value::Map(bank_map));
284
297
 
285
- Ok(())
298
+ Ok(module.clone())
286
299
  }
287
300
 
288
- fn extract_bank_names(statements: &[Statement]) -> HashSet<String> {
301
+ fn extract_bank_names(&self, statements: &[Statement]) -> HashSet<String> {
289
302
  let mut banks = HashSet::new();
290
303
 
291
304
  for stmt in statements {
292
- if let StatementKind::Trigger { entity, .. } = &stmt.kind {
293
- let parts: Vec<&str> = entity.split('.').collect();
294
- if parts.len() >= 2 {
295
- banks.insert(parts[0].to_string()); // "808.kick" → "808"
296
- }
297
- }
298
-
299
- if let StatementKind::Bank = &stmt.kind {
300
- if let Value::String(name) = &stmt.value {
301
- banks.insert(name.clone());
305
+ match &stmt.kind {
306
+ // Extract only bank declarations
307
+ StatementKind::Bank => {
308
+ if let Value::String(name) = &stmt.value {
309
+ banks.insert(name.clone());
310
+ }
311
+ if let Value::Number(num) = &stmt.value {
312
+ banks.insert(num.to_string());
313
+ }
314
+ if let Value::Identifier(name) = &stmt.value {
315
+ banks.insert(name.clone());
316
+ }
302
317
  }
318
+ _ => {}
303
319
  }
304
320
  }
305
321
 
@@ -1,7 +1,7 @@
1
1
  use crate::core::{
2
2
  lexer::token::Token,
3
3
  parser::statement::Statement,
4
- store::{ export::ExportTable, import::ImportTable, variable::VariableTable },
4
+ store::{ export::ExportTable, function::FunctionTable, import::ImportTable, variable::VariableTable },
5
5
  };
6
6
 
7
7
  #[derive(Debug, Clone)]
@@ -11,6 +11,7 @@ pub struct Module {
11
11
  pub tokens: Vec<Token>,
12
12
  pub statements: Vec<Statement>,
13
13
  pub variable_table: VariableTable,
14
+ pub function_table: FunctionTable,
14
15
  pub export_table: ExportTable,
15
16
  pub import_table: ImportTable,
16
17
  pub content: String,
@@ -24,6 +25,7 @@ impl Module {
24
25
  tokens: Vec::new(),
25
26
  statements: Vec::new(),
26
27
  variable_table: VariableTable::new(),
28
+ function_table: FunctionTable::new(),
27
29
  export_table: ExportTable::new(),
28
30
  import_table: ImportTable::new(),
29
31
  resolved: false,
@@ -5,7 +5,7 @@ use crate::core::{
5
5
  preprocessor::{ loader::ModuleLoader, resolver::group },
6
6
  shared::value::Value,
7
7
  store::global::GlobalStore,
8
- utils::path::{normalize_path, resolve_relative_path},
8
+ utils::path::{ normalize_path, resolve_relative_path },
9
9
  };
10
10
 
11
11
  pub fn process_modules(module_loader: &ModuleLoader, global_store: &mut GlobalStore) {
@@ -13,6 +13,31 @@ pub fn process_modules(module_loader: &ModuleLoader, global_store: &mut GlobalSt
13
13
  for stmt in &module.statements {
14
14
  match &stmt.kind {
15
15
  StatementKind::Let { name } => {
16
+ if let Value::Null = stmt.value {
17
+ eprintln!("❌ Variable '{}' is declared but not initialized.", name);
18
+
19
+ module.variable_table.variables.insert(
20
+ name.clone(),
21
+ Value::StatementKind(Box::new(stmt.kind.clone()))
22
+ );
23
+
24
+ continue;
25
+ }
26
+
27
+ if module.variable_table.get(name).is_some() {
28
+ eprintln!("❌ Variable '{}' is already defined in this scope.", name);
29
+ continue;
30
+ }
31
+
32
+ if let Some(module_variable) = module.variable_table.variables.get(name) {
33
+ eprintln!(
34
+ "❌ Variable '{}' is already defined globally with value: {:?}",
35
+ name,
36
+ module_variable
37
+ );
38
+ continue;
39
+ }
40
+
16
41
  module.variable_table.variables.insert(name.clone(), stmt.value.clone());
17
42
  }
18
43
 
@@ -10,103 +10,80 @@ use crate::{
10
10
 
11
11
  pub fn resolve_call(
12
12
  stmt: &Statement,
13
+ name: String,
14
+ args: Vec<Value>,
13
15
  module: &Module,
14
16
  path: &str,
15
17
  global_store: &mut GlobalStore
16
18
  ) -> Statement {
17
19
  let logger = Logger::new();
18
20
 
19
- match &stmt.value {
20
- Value::Identifier(ident) => {
21
- match module.variable_table.get(ident) {
22
- Some(Value::String(group_name)) =>
23
- resolve_group_by_name(group_name, stmt, module, path, global_store, &logger),
24
- Some(Value::Map(group_map)) =>
25
- resolved_call(stmt, group_map, module, path, global_store),
26
- Some(other) =>
27
- error_stmt(
28
- &logger,
29
- module,
30
- stmt,
31
- &format!(
32
- "Identifier '{ident}' must resolve to a group name or map, found {:?}",
33
- other
34
- )
35
- ),
36
- None =>
37
- error_stmt(
38
- &logger,
39
- module,
40
- stmt,
41
- &format!("Identifier '{ident}' not found in variable table")
42
- ),
43
- }
44
- }
21
+ match &stmt.kind {
22
+ StatementKind::Call { .. } => {
23
+ // Check if it's a function
24
+ if let Some(func) = global_store.functions.functions.get(&name) {
25
+ let mut call_map = std::collections::HashMap::new();
26
+ call_map.insert("name".to_string(), Value::Identifier(name.clone()));
27
+ call_map.insert(
28
+ "parameters".to_string(),
29
+ Value::Array(
30
+ func.parameters
31
+ .iter()
32
+ .map(|p| Value::Identifier(p.clone()))
33
+ .collect()
34
+ )
35
+ );
36
+ call_map.insert("args".to_string(), Value::Array(args.clone()));
37
+ call_map.insert("body".to_string(), Value::Block(func.body.clone()));
45
38
 
46
- Value::String(name) =>
47
- resolve_group_by_name(name, stmt, module, path, global_store, &logger),
39
+ return Statement {
40
+ kind: StatementKind::Call { name, args },
41
+ value: Value::Map(call_map),
42
+ ..stmt.clone()
43
+ };
44
+ }
48
45
 
49
- Value::Map(group_map) => resolved_call(stmt, group_map, module, path, global_store),
46
+ // Otherwise, check if it's a variable (e.g. group)
47
+ if let Some(variable) = global_store.variables.variables.get(&name) {
48
+ if let Value::Statement(stmt_box) = variable {
49
+ if let StatementKind::Group = stmt_box.kind {
50
+ if let Value::Map(map) = &stmt_box.value {
51
+ if let Some(Value::Block(body)) = map.get("body") {
52
+ let mut resolved_map = std::collections::HashMap::new();
53
+ resolved_map.insert(
54
+ "identifier".to_string(),
55
+ Value::String(name.clone())
56
+ );
57
+ resolved_map.insert("args".to_string(), Value::Array(args.clone()));
58
+ resolved_map.insert("body".to_string(), Value::Block(body.clone()));
50
59
 
51
- other =>
52
- error_stmt(
53
- &logger,
54
- module,
55
- stmt,
56
- &format!("Call expects a group name as string or identifier, found {:?}", other)
57
- ),
58
- }
59
- }
60
+ return Statement {
61
+ kind: StatementKind::Call { name, args },
62
+ value: Value::Map(resolved_map),
63
+ ..stmt.clone()
64
+ };
65
+ }
66
+ }
67
+ }
68
+ }
69
+ }
60
70
 
61
- fn resolve_group_by_name(
62
- name: &str,
63
- stmt: &Statement,
64
- module: &Module,
65
- path: &str,
66
- global_store: &mut GlobalStore,
67
- logger: &Logger
68
- ) -> Statement {
69
- match module.variable_table.get(name) {
70
- Some(Value::Map(group_map)) => resolved_call(stmt, group_map, module, path, global_store),
71
- Some(other) =>
72
- error_stmt(
73
- logger,
74
- module,
75
- stmt,
76
- &format!("Expected a group for '{}', but found {:?}", name, other)
77
- ),
78
- None =>
79
- error_stmt(
80
- logger,
81
- module,
82
- stmt,
83
- &format!("Group '{}' not found in module '{}'", name, module.path)
84
- ),
71
+ // Otherwise, log an error
72
+ logger.log_message(LogLevel::Error, &format!("Function or group '{}' not found", name));
73
+ Statement {
74
+ kind: StatementKind::Error {
75
+ message: format!("Function or group '{}' not found", name),
76
+ },
77
+ value: Value::Null,
78
+ ..stmt.clone()
79
+ }
80
+ }
81
+ _ => error_stmt(&logger, module, stmt, "Expected StatementKind::Call in resolve_call()"),
85
82
  }
86
83
  }
87
84
 
88
- fn resolved_call(
89
- stmt: &Statement,
90
- group_map: &std::collections::HashMap<String, Value>,
91
- module: &Module,
92
- path: &str,
93
- global_store: &mut GlobalStore
94
- ) -> Statement {
95
- let mut cloned_map = group_map.clone();
96
-
97
- if let Some(Value::Block(stmts)) = group_map.get("body") {
98
- let resolved = stmts
99
- .iter()
100
- .map(|s| resolve_statement(s, module, path, global_store))
101
- .collect();
102
- cloned_map.insert("body".to_string(), Value::Block(resolved));
103
- }
104
-
105
- Statement {
106
- kind: StatementKind::Call,
107
- value: Value::Map(cloned_map),
108
- ..stmt.clone()
109
- }
85
+ fn get_group_body(stmt_box: &Statement) -> Vec<Statement> {
86
+ if let Value::Block(body) = &stmt_box.value { body.clone() } else { vec![] }
110
87
  }
111
88
 
112
89
  fn error_stmt(logger: &Logger, module: &Module, stmt: &Statement, message: &str) -> Statement {
@@ -1,7 +1,7 @@
1
1
  use crate::{
2
2
  core::{
3
- parser::statement::{Statement, StatementKind},
4
- preprocessor::{module::Module, resolver::driver::resolve_statement},
3
+ parser::statement::{ Statement, StatementKind },
4
+ preprocessor::{ module::Module, resolver::driver::resolve_statement },
5
5
  shared::value::Value,
6
6
  store::global::GlobalStore,
7
7
  },
@@ -12,12 +12,17 @@ pub fn resolve_condition(
12
12
  stmt: &Statement,
13
13
  module: &Module,
14
14
  path: &str,
15
- global_store: &mut GlobalStore,
15
+ global_store: &mut GlobalStore
16
16
  ) -> Statement {
17
17
  let logger = Logger::new();
18
18
 
19
19
  let Value::Map(condition_map) = &stmt.value else {
20
- return type_error(&logger, module, stmt, "Expected a map in condition statement".to_string());
20
+ return type_error(
21
+ &logger,
22
+ module,
23
+ stmt,
24
+ "Expected a map in condition statement".to_string()
25
+ );
21
26
  };
22
27
 
23
28
  let mut resolved_map = condition_map.clone();
@@ -60,13 +65,13 @@ fn resolve_block_statements(
60
65
  body: &[Statement],
61
66
  module: &Module,
62
67
  path: &str,
63
- global_store: &mut GlobalStore,
68
+ global_store: &mut GlobalStore
64
69
  ) -> Vec<Statement> {
65
70
  body.iter()
66
71
  .flat_map(|stmt| {
67
72
  let resolved = resolve_statement(stmt, module, path, global_store);
68
73
 
69
- if let StatementKind::Call = resolved.kind {
74
+ if let StatementKind::Call { .. } = resolved.kind {
70
75
  if let Value::Block(inner) = &resolved.value {
71
76
  return inner
72
77
  .iter()
@@ -9,6 +9,7 @@ use crate::{
9
9
  bank::resolve_bank,
10
10
  call::resolve_call,
11
11
  condition::resolve_condition,
12
+ function::resolve_function,
12
13
  group::resolve_group,
13
14
  let_::resolve_let,
14
15
  loop_::resolve_loop,
@@ -36,12 +37,22 @@ pub fn resolve_statement(
36
37
  global_store: &mut GlobalStore
37
38
  ) -> Statement {
38
39
  match &stmt.kind {
39
- StatementKind::Trigger { entity, duration } =>
40
- resolve_trigger(stmt, entity, &mut duration.clone(), module, path, global_store),
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
+ ),
41
50
  StatementKind::If => resolve_condition(stmt, module, path, global_store),
42
51
  StatementKind::Group => resolve_group(stmt, module, path, global_store),
43
- StatementKind::Call => resolve_call(stmt, module, path, global_store),
44
- StatementKind::Spawn => resolve_spawn(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),
45
56
  StatementKind::Bank => resolve_bank(stmt, module, path, global_store),
46
57
  StatementKind::Tempo => resolve_tempo(stmt, module, path, global_store),
47
58
  StatementKind::Loop => resolve_loop(stmt, module, path, global_store),
@@ -180,14 +191,20 @@ pub fn resolve_and_flatten_all_modules(
180
191
  let mut resolved = Vec::new();
181
192
 
182
193
  for stmt in &module.statements {
183
- let mut stmt = stmt.clone();
194
+ let stmt = stmt.clone();
184
195
 
185
196
  match &stmt.kind {
186
- StatementKind::Trigger { entity, duration } => {
197
+ StatementKind::Let { name } => {
198
+ let resolved_stmt = resolve_let(&stmt, name, &module, &path, global_store);
199
+ resolved.push(resolved_stmt);
200
+ }
201
+
202
+ StatementKind::Trigger { entity, duration, effects } => {
187
203
  let resolved_stmt = resolve_trigger(
188
204
  &stmt,
189
205
  entity.as_str(),
190
206
  &mut duration.clone(),
207
+ effects.clone(),
191
208
  &module,
192
209
  &path,
193
210
  global_store
@@ -214,11 +231,40 @@ pub fn resolve_and_flatten_all_modules(
214
231
  resolved.push(stmt.clone());
215
232
  }
216
233
 
234
+ StatementKind::Call { name, args } => {
235
+ let resolved_stmt = resolve_call(
236
+ &stmt,
237
+ name.clone(),
238
+ args.clone(),
239
+ &module,
240
+ &path,
241
+ global_store
242
+ );
243
+ resolved.push(resolved_stmt);
244
+ }
245
+
246
+ StatementKind::Spawn { name, args } => {
247
+ let resolved_stmt = resolve_spawn(
248
+ &stmt,
249
+ name.clone(),
250
+ args.clone(),
251
+ &module,
252
+ &path,
253
+ global_store
254
+ );
255
+ resolved.push(resolved_stmt);
256
+ }
257
+
217
258
  StatementKind::Group => {
218
259
  let resolved_stmt = resolve_group(&stmt, &module, &path, global_store);
219
260
  resolved.push(resolved_stmt);
220
261
  }
221
262
 
263
+ StatementKind::Function { name, parameters, body } => {
264
+ let resolved_function = resolve_function(&stmt, &module, &path, global_store);
265
+ resolved.push(resolved_function);
266
+ }
267
+
222
268
  _ => {
223
269
  resolved.push(stmt);
224
270
  }
@@ -0,0 +1,78 @@
1
+ use std::collections::HashMap;
2
+
3
+ use crate::{
4
+ core::{
5
+ parser::statement::{ Statement, StatementKind },
6
+ preprocessor::{ module::Module, resolver::driver::resolve_statement },
7
+ shared::value::Value,
8
+ store::{ function::FunctionDef, global::GlobalStore, variable::VariableTable },
9
+ },
10
+ utils::logger::{ LogLevel, Logger },
11
+ };
12
+
13
+ pub fn resolve_function(
14
+ stmt: &Statement,
15
+ module: &Module,
16
+ path: &str,
17
+ global_store: &mut GlobalStore
18
+ ) -> Statement {
19
+ if let StatementKind::Function { name, parameters, body } = &stmt.kind {
20
+ let resolved_body = resolve_block_statements(body, &module, path, global_store);
21
+
22
+ global_store.functions.add_function(FunctionDef {
23
+ name: name.clone(),
24
+ parameters: parameters.clone(),
25
+ body: resolved_body.clone(),
26
+ });
27
+
28
+ if let Some(current_mod) = global_store.modules.get_mut(path) {
29
+ current_mod.function_table.add_function(FunctionDef {
30
+ name: name.clone(),
31
+ parameters: parameters.clone(),
32
+ body: resolved_body.clone(),
33
+ });
34
+ } else {
35
+ eprintln!("[resolve_statement] ❌ Module path not found: {path}");
36
+ }
37
+
38
+ return Statement {
39
+ kind: StatementKind::Function {
40
+ name: name.clone(),
41
+ parameters: parameters.clone(),
42
+ body: resolved_body,
43
+ },
44
+ value: Value::Null,
45
+ ..stmt.clone()
46
+ };
47
+ } else {
48
+ return Statement {
49
+ kind: StatementKind::Error {
50
+ message: "Expected a function statement".to_string(),
51
+ },
52
+ value: Value::Null,
53
+ ..stmt.clone()
54
+ };
55
+ }
56
+ }
57
+
58
+ fn resolve_block_statements(
59
+ body: &[Statement],
60
+ module: &Module,
61
+ path: &str,
62
+ global_store: &mut GlobalStore
63
+ ) -> Vec<Statement> {
64
+ body.iter()
65
+ .map(|stmt| resolve_statement(stmt, module, path, global_store))
66
+ .collect()
67
+ }
68
+
69
+ fn type_error(logger: &Logger, module: &Module, stmt: &Statement, message: String) -> Statement {
70
+ let stacktrace = format!("{}:{}:{}", module.path, stmt.line, stmt.column);
71
+ logger.log_error_with_stacktrace(&message, &stacktrace);
72
+
73
+ Statement {
74
+ kind: StatementKind::Error { message },
75
+ value: Value::Null,
76
+ ..stmt.clone()
77
+ }
78
+ }