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

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 (93) hide show
  1. package/.devalang +8 -9
  2. package/Cargo.toml +8 -3
  3. package/README.md +36 -34
  4. package/docs/CHANGELOG.md +65 -1
  5. package/docs/CONTRIBUTING.md +1 -0
  6. package/docs/ROADMAP.md +2 -2
  7. package/docs/TODO.md +6 -5
  8. package/examples/bank.deva +2 -4
  9. package/examples/function.deva +15 -0
  10. package/examples/index.deva +25 -14
  11. package/out-tsc/bin/devalang.exe +0 -0
  12. package/package.json +6 -6
  13. package/project-version.json +3 -3
  14. package/rust/cli/bank.rs +2 -1
  15. package/rust/cli/build.rs +76 -14
  16. package/rust/cli/check.rs +71 -8
  17. package/rust/cli/driver.rs +40 -28
  18. package/rust/cli/install.rs +22 -7
  19. package/rust/cli/login.rs +134 -0
  20. package/rust/cli/mod.rs +2 -1
  21. package/rust/cli/play.rs +45 -20
  22. package/rust/common/api.rs +8 -0
  23. package/rust/common/cdn.rs +2 -5
  24. package/rust/common/mod.rs +3 -1
  25. package/rust/common/sso.rs +8 -0
  26. package/rust/config/driver.rs +19 -1
  27. package/rust/config/loader.rs +56 -10
  28. package/rust/core/audio/engine.rs +254 -91
  29. package/rust/core/audio/interpreter/arrow_call.rs +34 -15
  30. package/rust/core/audio/interpreter/call.rs +72 -47
  31. package/rust/core/audio/interpreter/condition.rs +14 -12
  32. package/rust/core/audio/interpreter/driver.rs +90 -128
  33. package/rust/core/audio/interpreter/function.rs +21 -0
  34. package/rust/core/audio/interpreter/load.rs +1 -1
  35. package/rust/core/audio/interpreter/loop_.rs +24 -18
  36. package/rust/core/audio/interpreter/mod.rs +2 -1
  37. package/rust/core/audio/interpreter/sleep.rs +0 -6
  38. package/rust/core/audio/interpreter/spawn.rs +78 -60
  39. package/rust/core/audio/interpreter/trigger.rs +157 -70
  40. package/rust/core/audio/loader/trigger.rs +37 -4
  41. package/rust/core/audio/player.rs +20 -10
  42. package/rust/core/audio/renderer.rs +24 -25
  43. package/rust/core/builder/mod.rs +11 -6
  44. package/rust/core/debugger/mod.rs +2 -0
  45. package/rust/core/debugger/module.rs +47 -0
  46. package/rust/core/debugger/store.rs +25 -11
  47. package/rust/core/error/mod.rs +6 -0
  48. package/rust/core/lexer/handler/driver.rs +23 -1
  49. package/rust/core/lexer/handler/identifier.rs +1 -0
  50. package/rust/core/lexer/handler/indent.rs +16 -2
  51. package/rust/core/lexer/handler/mod.rs +1 -0
  52. package/rust/core/lexer/handler/parenthesis.rs +41 -0
  53. package/rust/core/lexer/token.rs +4 -0
  54. package/rust/core/mod.rs +2 -1
  55. package/rust/core/parser/driver.rs +47 -4
  56. package/rust/core/parser/handler/arrow_call.rs +78 -18
  57. package/rust/core/parser/handler/bank.rs +35 -7
  58. package/rust/core/parser/handler/dot.rs +81 -123
  59. package/rust/core/parser/handler/identifier/call.rs +69 -22
  60. package/rust/core/parser/handler/identifier/function.rs +92 -0
  61. package/rust/core/parser/handler/identifier/let_.rs +13 -19
  62. package/rust/core/parser/handler/identifier/mod.rs +1 -0
  63. package/rust/core/parser/handler/identifier/spawn.rs +74 -27
  64. package/rust/core/parser/statement.rs +16 -4
  65. package/rust/core/plugin/loader.rs +48 -0
  66. package/rust/core/plugin/mod.rs +1 -0
  67. package/rust/core/preprocessor/loader.rs +50 -32
  68. package/rust/core/preprocessor/module.rs +3 -1
  69. package/rust/core/preprocessor/processor.rs +26 -1
  70. package/rust/core/preprocessor/resolver/call.rs +61 -84
  71. package/rust/core/preprocessor/resolver/condition.rs +11 -6
  72. package/rust/core/preprocessor/resolver/driver.rs +52 -6
  73. package/rust/core/preprocessor/resolver/function.rs +78 -0
  74. package/rust/core/preprocessor/resolver/group.rs +43 -13
  75. package/rust/core/preprocessor/resolver/let_.rs +7 -10
  76. package/rust/core/preprocessor/resolver/mod.rs +2 -1
  77. package/rust/core/preprocessor/resolver/spawn.rs +64 -30
  78. package/rust/core/preprocessor/resolver/trigger.rs +7 -3
  79. package/rust/core/preprocessor/resolver/value.rs +10 -1
  80. package/rust/core/shared/value.rs +4 -1
  81. package/rust/core/store/function.rs +34 -0
  82. package/rust/core/store/global.rs +9 -10
  83. package/rust/core/store/mod.rs +2 -1
  84. package/rust/core/store/variable.rs +6 -0
  85. package/rust/installer/addon.rs +80 -0
  86. package/rust/installer/bank.rs +24 -14
  87. package/rust/installer/mod.rs +4 -1
  88. package/rust/installer/plugin.rs +55 -0
  89. package/rust/lib.rs +10 -7
  90. package/rust/main.rs +32 -9
  91. package/rust/utils/logger.rs +16 -0
  92. package/rust/utils/mod.rs +45 -1
  93. package/rust/utils/spinner.rs +2 -4
@@ -23,11 +23,16 @@ pub fn interprete_call_arrow_statement(
23
23
  .unwrap_or(0.0);
24
24
 
25
25
  if let StatementKind::ArrowCall { target, method, args } = &stmt.kind {
26
- let Some(Value::Map(synth_map)) = variable_table.get(target) else {
26
+ let Some(Value::Statement(synth_stmt)) = variable_table.get(target) else {
27
27
  println!("❌ Synth '{}' not found in variable table", target);
28
28
  return (*max_end_time, cursor_copy);
29
29
  };
30
30
 
31
+ let Value::Map(synth_map) = &synth_stmt.value else {
32
+ println!("❌ Invalid synth statement for '{}', expected a map.", target);
33
+ return (*max_end_time, cursor_copy);
34
+ };
35
+
31
36
  let Some(Value::String(entity)) = synth_map.get("entity") else {
32
37
  println!("❌ Missing 'entity' key in synth '{}'.", target);
33
38
  return (*max_end_time, cursor_copy);
@@ -53,37 +58,51 @@ pub fn interprete_call_arrow_statement(
53
58
  return (*max_end_time, cursor_copy);
54
59
  };
55
60
 
56
- let freq = extract_f32(params, "freq", base_bpm).unwrap_or(440.0);
57
- let amp = extract_f32(params, "amp", base_bpm).unwrap_or(1.0);
61
+ // Synth parameters
62
+ let synth_params = params.clone();
63
+ let amp = extract_f32(&synth_params, "amp", base_bpm).unwrap_or(1.0);
58
64
 
59
65
  if method == "note" {
60
- let Some(Value::Identifier(note_name)) = args.get(0) else {
66
+ let filtered_args: Vec<_> = args
67
+ .iter()
68
+ .filter(|arg| !matches!(arg, Value::Unknown))
69
+ .collect();
70
+
71
+ let Some(Value::Identifier(note_name)) = filtered_args.get(0).map(|v| (*v).clone()) else {
61
72
  println!("❌ Invalid or missing argument for 'note' method on '{}'.", target);
62
73
  return (*max_end_time, cursor_copy);
63
74
  };
64
75
 
65
- let mut final_note_params = HashMap::new();
66
- if let Some(Value::Map(note_params)) = args.get(1) {
67
- for (key, value) in note_params {
68
- final_note_params.insert(key.clone(), value.clone());
76
+ let mut note_params = HashMap::new();
77
+ if let Some(arg1) = filtered_args.get(1) {
78
+ match (*arg1).clone() {
79
+ Value::Map(map) => {
80
+ for (key, value) in map {
81
+ note_params.insert(key, value);
82
+ }
83
+ }
84
+ _ => {}
69
85
  }
70
86
  }
71
87
 
72
- let duration_ms = extract_f32(&final_note_params, "duration", base_bpm).unwrap_or(
73
- base_duration
74
- );
88
+ // Note parameters and calculations
89
+ let amp_note = extract_f32(&note_params, "amp", base_bpm).unwrap_or(amp);
90
+ let duration_ms = extract_f32(&note_params, "duration", base_bpm)
91
+ .unwrap_or(base_duration * 1000.0);
92
+
75
93
  let duration_secs = duration_ms / 1000.0;
76
-
77
- let final_freq = note_to_freq(note_name);
94
+ let final_freq = note_to_freq(&note_name);
78
95
  let start_time = cursor_copy;
79
96
  let end_time = start_time + duration_secs;
80
97
 
81
98
  audio_engine.insert_note(
82
99
  waveform.clone(),
83
100
  final_freq,
84
- amp,
101
+ amp_note,
85
102
  start_time * 1000.0,
86
- duration_ms
103
+ duration_ms,
104
+ synth_params,
105
+ note_params
87
106
  );
88
107
 
89
108
  *max_end_time = (*max_end_time).max(end_time);
@@ -1,70 +1,95 @@
1
1
  use crate::core::{
2
- audio::{ engine::AudioEngine, interpreter::{ driver::execute_audio_block } },
3
- parser::statement::{ Statement, StatementKind },
4
- shared::{ duration::Duration, value::Value },
5
- store::variable::VariableTable,
2
+ audio::{engine::AudioEngine, interpreter::driver::execute_audio_block},
3
+ parser::statement::{Statement, StatementKind},
4
+ shared::value::Value,
5
+ store::{function::FunctionTable, global::GlobalStore, variable::VariableTable},
6
6
  };
7
7
 
8
8
  pub fn interprete_call_statement(
9
9
  stmt: &Statement,
10
- audio_engine: AudioEngine,
11
- variable_table: VariableTable,
10
+ audio_engine: &mut AudioEngine,
11
+ variable_table: &VariableTable,
12
+ functions: &FunctionTable,
13
+ global_store: &GlobalStore,
12
14
  base_bpm: f32,
13
15
  base_duration: f32,
14
16
  max_end_time: f32,
15
17
  cursor_time: f32,
16
- all_statements: &Vec<Statement>
17
- ) -> (AudioEngine, f32, f32, f32) {
18
- match &stmt.value {
19
- Value::String(identifier) | Value::Identifier(identifier) => {
20
- if
21
- let Some(group_stmt) = all_statements
22
- .iter()
23
- .find(|s| {
24
- matches!(s.kind, StatementKind::Group) &&
25
- s.value.get("identifier") == Some(&Value::String(identifier.clone()))
26
- })
27
- {
28
- if let Some(Value::Block(block)) = group_stmt.value.get("body") {
29
- let (eng, _, end_time) = execute_audio_block(
30
- audio_engine,
31
- variable_table,
32
- block.clone(),
33
- base_bpm,
34
- base_duration,
35
- max_end_time,
36
- cursor_time
18
+ ) -> (f32, f32) {
19
+ match &stmt.kind {
20
+ StatementKind::Call { name, args } => {
21
+ // Classic function call case
22
+ if let Some(func) = functions.functions.get(name) {
23
+ if func.parameters.len() != args.len() {
24
+ eprintln!(
25
+ "❌ Function '{}' expects {} args, got {}",
26
+ name,
27
+ func.parameters.len(),
28
+ args.len()
37
29
  );
38
- return (eng, max_end_time.max(end_time), end_time, cursor_time);
39
- } else {
40
- eprintln!("❌ Group '{}' found but no valid body block", identifier);
30
+ return (max_end_time, cursor_time);
31
+ }
32
+
33
+ let mut local_vars = VariableTable::with_parent(variable_table.clone());
34
+ for (param, arg) in func.parameters.iter().zip(args) {
35
+ local_vars.set(param.clone(), arg.clone());
41
36
  }
42
- } else {
43
- eprintln!("❌ Group '{}' not found in statements", identifier);
44
- }
45
- }
46
37
 
47
- Value::Map(map) => {
48
- if let Some(Value::Block(block)) = map.get("body") {
49
- let (eng, _, end_time) = execute_audio_block(
38
+ return execute_audio_block(
50
39
  audio_engine,
51
- variable_table,
52
- block.clone(),
40
+ global_store,
41
+ local_vars,
42
+ functions.clone(),
43
+ func.body.clone(),
53
44
  base_bpm,
54
45
  base_duration,
55
46
  max_end_time,
56
- cursor_time
47
+ cursor_time,
57
48
  );
58
- return (eng, max_end_time.max(end_time), end_time, cursor_time);
59
- } else {
60
- eprintln!("❌ Call map has no 'body' block");
61
49
  }
62
- }
63
50
 
64
- other => {
65
- eprintln!("❌ Invalid call statement: expected identifier or map, found {:?}", other);
51
+ // Group case
52
+ if let Some(group_stmt) = find_group(name, variable_table, global_store) {
53
+ if let Value::Map(map) = &group_stmt.value {
54
+ if let Some(Value::Block(body)) = map.get("body") {
55
+ return execute_audio_block(
56
+ audio_engine,
57
+ global_store,
58
+ variable_table.clone(),
59
+ functions.clone(),
60
+ body.clone(),
61
+ base_bpm,
62
+ base_duration,
63
+ max_end_time,
64
+ cursor_time,
65
+ );
66
+ }
67
+ }
68
+ }
69
+
70
+ eprintln!("❌ Function or group '{}' not found", name);
66
71
  }
72
+
73
+ _ => eprintln!("❌ interprete_call_statement expected Call, got {:?}", stmt.kind),
67
74
  }
68
75
 
69
- (audio_engine, base_bpm, max_end_time, cursor_time)
76
+ (max_end_time, cursor_time)
77
+ }
78
+
79
+ fn find_group<'a>(
80
+ name: &str,
81
+ variable_table: &'a VariableTable,
82
+ global_store: &'a GlobalStore,
83
+ ) -> Option<&'a Statement> {
84
+ if let Some(Value::Statement(stmt_box)) = variable_table.get(name) {
85
+ if let StatementKind::Group = stmt_box.kind {
86
+ return Some(stmt_box);
87
+ }
88
+ }
89
+ if let Some(Value::Statement(stmt_box)) = global_store.variables.variables.get(name) {
90
+ if let StatementKind::Group = stmt_box.kind {
91
+ return Some(stmt_box);
92
+ }
93
+ }
94
+ None
70
95
  }
@@ -6,20 +6,20 @@ use crate::core::{
6
6
  },
7
7
  parser::statement::Statement,
8
8
  shared::value::Value,
9
- store::variable::VariableTable,
9
+ store::{ function::FunctionTable, global::GlobalStore, variable::VariableTable },
10
10
  };
11
11
 
12
12
  pub fn interprete_condition_statement(
13
13
  stmt: &Statement,
14
- audio_engine: AudioEngine,
15
- variable_table: VariableTable,
14
+ audio_engine: &mut AudioEngine,
15
+ global_store: &GlobalStore,
16
+ variable_table: &VariableTable,
17
+ functions_table: &FunctionTable,
16
18
  base_bpm: f32,
17
19
  base_duration: f32,
18
20
  max_end_time: f32,
19
21
  cursor_time: f32
20
- ) -> (AudioEngine, f32, f32) {
21
- let mut engine = audio_engine.clone();
22
- let mut vars = variable_table.clone();
22
+ ) -> (f32, f32) {
23
23
  let mut cur_time = cursor_time;
24
24
  let mut max_time = max_end_time;
25
25
 
@@ -32,23 +32,25 @@ pub fn interprete_condition_statement(
32
32
 
33
33
  let should_execute = match map.get("condition") {
34
34
  Some(Value::Boolean(b)) => *b,
35
- Some(Value::String(expr)) => evaluate_condition_string(expr, &vars),
35
+ Some(Value::String(expr)) => evaluate_condition_string(expr, &variable_table.clone()),
36
36
  Some(_) => false,
37
37
  None => true,
38
38
  };
39
39
 
40
40
  if should_execute {
41
41
  if let Some(Value::Block(block)) = map.get("body") {
42
- let (new_engine, _, new_max) = execute_audio_block(
43
- engine,
44
- vars,
42
+ let (new_max, cursor_time) = execute_audio_block(
43
+ audio_engine,
44
+ global_store,
45
+ variable_table.clone(),
46
+ functions_table.clone(),
45
47
  block.clone(),
46
48
  base_bpm,
47
49
  base_duration,
48
50
  max_time,
49
51
  cur_time
50
52
  );
51
- return (new_engine, new_max, new_max);
53
+ return (new_max, cursor_time);
52
54
  } else {
53
55
  break;
54
56
  }
@@ -65,5 +67,5 @@ pub fn interprete_condition_statement(
65
67
  }
66
68
  }
67
69
 
68
- (audio_engine, max_end_time, cursor_time)
70
+ (max_end_time, cursor_time)
69
71
  }
@@ -1,3 +1,6 @@
1
+ use rayon::prelude::*;
2
+ use std::sync::{ Arc, Mutex };
3
+
1
4
  use crate::core::{
2
5
  audio::{
3
6
  engine::AudioEngine,
@@ -5,6 +8,7 @@ use crate::core::{
5
8
  arrow_call::interprete_call_arrow_statement,
6
9
  call::interprete_call_statement,
7
10
  condition::interprete_condition_statement,
11
+ function::interprete_function_statement,
8
12
  let_::interprete_let_statement,
9
13
  load::interprete_load_statement,
10
14
  loop_::interprete_loop_statement,
@@ -15,37 +19,26 @@ use crate::core::{
15
19
  },
16
20
  },
17
21
  parser::statement::{ Statement, StatementKind },
18
- store::variable::VariableTable,
22
+ store::{ function::FunctionTable, global::GlobalStore, variable::VariableTable },
19
23
  };
20
24
 
21
25
  pub fn run_audio_program(
22
26
  statements: &Vec<Statement>,
23
- mut audio_engine: AudioEngine,
27
+ audio_engine: &mut AudioEngine,
24
28
  entry: String,
25
- output: String
26
- ) -> (AudioEngine, f32, f32) {
29
+ output: String,
30
+ mut module_variables: VariableTable,
31
+ mut module_functions: FunctionTable,
32
+ global_store: &mut GlobalStore
33
+ ) -> (f32, f32) {
27
34
  let mut base_bpm = 120.0;
28
35
  let mut base_duration = 60.0 / base_bpm;
29
36
 
30
- let mut variable_table = audio_engine.variables.clone();
31
-
32
- for stmt in statements {
33
- if let StatementKind::Let { .. } = stmt.kind {
34
- if
35
- let Some(new_table) =
36
- interprete_let_statement(
37
- stmt,
38
- &mut variable_table
39
- )
40
- {
41
- variable_table = new_table;
42
- }
43
- }
44
- }
45
-
46
- let (updated_audio_engine, base_bpm, max_end_time) = execute_audio_block(
37
+ let (max_end_time, cursor_time) = execute_audio_block(
47
38
  audio_engine,
48
- variable_table,
39
+ global_store,
40
+ global_store.variables.clone(),
41
+ global_store.functions.clone(),
49
42
  statements.clone(),
50
43
  base_bpm,
51
44
  base_duration,
@@ -53,112 +46,65 @@ pub fn run_audio_program(
53
46
  0.0
54
47
  );
55
48
 
56
- (updated_audio_engine, base_bpm, max_end_time)
49
+ (max_end_time, cursor_time)
57
50
  }
58
51
 
59
52
  pub fn execute_audio_block(
60
- mut audio_engine: AudioEngine,
53
+ audio_engine: &mut AudioEngine,
54
+ global_store: &GlobalStore,
61
55
  mut variable_table: VariableTable,
62
- mut statements: Vec<Statement>,
56
+ mut functions_table: FunctionTable,
57
+ statements: Vec<Statement>,
63
58
  mut base_bpm: f32,
64
59
  mut base_duration: f32,
65
60
  mut max_end_time: f32,
66
61
  mut cursor_time: f32
67
- ) -> (AudioEngine, f32, f32) {
68
- let initial_cursor_time = cursor_time;
62
+ ) -> (f32, f32) {
63
+ let (spawns, others): (Vec<_>, Vec<_>) = statements
64
+ .into_iter()
65
+ .partition(|stmt| matches!(stmt.kind, StatementKind::Spawn { .. }));
69
66
 
70
- for stmt in statements.clone() {
67
+ // Execute sequential statements first
68
+ for stmt in others {
71
69
  match &stmt.kind {
72
70
  StatementKind::Load { .. } => {
73
- if
74
- let Some(new_variable_table) = interprete_load_statement(
75
- &stmt,
76
- &mut variable_table
77
- )
78
- {
79
- variable_table = new_variable_table;
80
- } else {
81
- eprintln!("❌ Failed to interpret load statement: {:?}", stmt);
71
+ if let Some(new_table) = interprete_load_statement(&stmt, &mut variable_table) {
72
+ variable_table = new_table;
82
73
  }
83
74
  }
84
-
85
75
  StatementKind::Let { .. } => {
86
- if
87
- let Some(new_variable_table) = interprete_let_statement(
88
- &stmt,
89
- &mut variable_table
90
- )
76
+ if let Some(new_table) = interprete_let_statement(&stmt, &mut variable_table) {
77
+ variable_table = new_table;
78
+ }
79
+ }
80
+ StatementKind::Function { .. } => {
81
+ if let Some(new_functions) =
82
+ interprete_function_statement(&stmt, &mut functions_table)
91
83
  {
92
- variable_table = new_variable_table;
93
- } else {
94
- eprintln!("❌ Failed to interpret let statement: {:?}", stmt);
84
+ functions_table = new_functions;
95
85
  }
96
86
  }
97
-
98
87
  StatementKind::Tempo => {
99
88
  if let Some((new_bpm, new_duration)) = interprete_tempo_statement(&stmt) {
100
89
  base_bpm = new_bpm;
101
90
  base_duration = new_duration;
102
- } else {
103
- eprintln!("❌ Failed to interpret tempo statement: {:?}", stmt);
104
91
  }
105
92
  }
106
-
107
93
  StatementKind::Trigger { .. } => {
108
94
  if
109
- let Some((new_cursor_time, new_max_end_time, updated_engine)) =
110
- interprete_trigger_statement(
111
- &stmt,
112
- &mut audio_engine,
113
- &variable_table,
114
- base_duration,
115
- cursor_time,
116
- max_end_time
117
- )
118
- {
119
- cursor_time = new_cursor_time;
120
- max_end_time = new_max_end_time;
121
- audio_engine = updated_engine;
122
- } else {
123
- eprintln!("❌ Failed to interpret trigger statement: {:?}", stmt);
124
- }
125
- }
126
-
127
- StatementKind::Spawn => {
128
- let mut temp_engine = AudioEngine::new(audio_engine.module_name.clone());
129
-
130
- if
131
- let Some((_cur, _max, updated_engine)) = interprete_spawn_statement(
95
+ let Some((new_cursor, new_max, _)) = interprete_trigger_statement(
132
96
  &stmt,
133
- temp_engine,
97
+ audio_engine,
134
98
  &variable_table,
135
- base_bpm,
136
99
  base_duration,
137
- initial_cursor_time,
100
+ cursor_time,
138
101
  max_end_time
139
102
  )
140
103
  {
141
- audio_engine.merge_with(updated_engine);
104
+ cursor_time = new_cursor;
105
+ max_end_time = new_max;
142
106
  }
143
107
  }
144
-
145
- StatementKind::Call => {
146
- let (call_engine, new_max, end_time, new_cursor) = interprete_call_statement(
147
- &stmt,
148
- audio_engine.clone(),
149
- variable_table.clone(),
150
- base_bpm,
151
- base_duration,
152
- max_end_time,
153
- cursor_time,
154
- &statements
155
- );
156
-
157
- audio_engine.merge_with(call_engine);
158
- cursor_time = new_cursor;
159
- max_end_time = new_max;
160
- }
161
-
162
108
  StatementKind::Sleep => {
163
109
  let (new_cursor, new_max) = interprete_sleep_statement(
164
110
  &stmt,
@@ -168,42 +114,40 @@ pub fn execute_audio_block(
168
114
  cursor_time = new_cursor;
169
115
  max_end_time = new_max;
170
116
  }
171
-
172
117
  StatementKind::Loop => {
173
- let (loop_engine, new_max, new_cursor) = interprete_loop_statement(
118
+ let (new_max, new_cursor) = interprete_loop_statement(
174
119
  &stmt,
175
- audio_engine.clone(),
176
- variable_table.clone(),
120
+ audio_engine,
121
+ global_store,
122
+ &variable_table,
123
+ &functions_table,
177
124
  base_bpm,
178
125
  base_duration,
179
126
  max_end_time,
180
127
  cursor_time
181
128
  );
182
- audio_engine = loop_engine;
183
129
  cursor_time = new_cursor;
184
130
  max_end_time = new_max;
185
131
  }
186
-
187
- StatementKind::If | StatementKind::ElseIf | StatementKind::Else => {
188
- let (condition_engine, new_max, new_cursor) = interprete_condition_statement(
132
+ StatementKind::Call { .. } => {
133
+ let (new_max, _) = interprete_call_statement(
189
134
  &stmt,
190
- audio_engine.clone(),
191
- variable_table.clone(),
135
+ audio_engine,
136
+ &variable_table,
137
+ &functions_table,
138
+ global_store,
192
139
  base_bpm,
193
140
  base_duration,
194
141
  max_end_time,
195
- cursor_time
142
+ cursor_time,
196
143
  );
197
-
198
- audio_engine = condition_engine;
199
- cursor_time = new_cursor;
144
+ cursor_time = new_max;
200
145
  max_end_time = new_max;
201
146
  }
202
-
203
147
  StatementKind::ArrowCall { .. } => {
204
- let (new_max_end_time, new_cursor_time) = interprete_call_arrow_statement(
148
+ let (new_max, new_cursor) = interprete_call_arrow_statement(
205
149
  &stmt,
206
- &mut audio_engine,
150
+ audio_engine,
207
151
  &variable_table,
208
152
  base_bpm,
209
153
  base_duration,
@@ -212,25 +156,43 @@ pub fn execute_audio_block(
212
156
  true
213
157
  );
214
158
 
215
- cursor_time = new_cursor_time;
216
- max_end_time = new_max_end_time;
217
- }
218
-
219
- | StatementKind::Bank
220
- | StatementKind::Import { .. }
221
- | StatementKind::Export { .. }
222
- | StatementKind::Group
223
- | StatementKind::Unknown => {
224
- // NOTE: Ignoring unsupported statement kinds for now.
225
- }
226
-
227
- _ => {
228
- eprintln!("Unsupported audio statement kind: {:?}", stmt);
159
+ cursor_time = new_cursor;
160
+
161
+ if new_max > max_end_time {
162
+ max_end_time = new_max;
163
+ }
229
164
  }
165
+ _ => {}
230
166
  }
231
167
  }
232
168
 
233
- audio_engine.set_variables(variable_table);
169
+ // Execute parallel spawns (collect results)
170
+ let spawn_results: Vec<(AudioEngine, f32)> = spawns
171
+ .par_iter()
172
+ .map(|stmt| {
173
+ let mut local_engine = AudioEngine::new(audio_engine.module_name.clone());
174
+ let (spawn_max, _) = interprete_spawn_statement(
175
+ stmt,
176
+ &mut local_engine,
177
+ &variable_table,
178
+ &functions_table,
179
+ global_store,
180
+ base_bpm,
181
+ base_duration,
182
+ 0.0,
183
+ 0.0
184
+ );
185
+ (local_engine, spawn_max)
186
+ })
187
+ .collect();
188
+
189
+ // Finally, merge results from all spawns
190
+ for (local_engine, spawn_max) in spawn_results {
191
+ audio_engine.merge_with(local_engine);
192
+ if spawn_max > max_end_time {
193
+ max_end_time = spawn_max;
194
+ }
195
+ }
234
196
 
235
- (audio_engine, base_bpm, max_end_time)
197
+ (max_end_time.max(cursor_time), cursor_time)
236
198
  }
@@ -0,0 +1,21 @@
1
+ use crate::core::{
2
+ parser::statement::{ Statement, StatementKind },
3
+ store::function::{ FunctionDef, FunctionTable },
4
+ };
5
+
6
+ pub fn interprete_function_statement(
7
+ stmt: &Statement,
8
+ functions_table: &mut FunctionTable
9
+ ) -> Option<FunctionTable> {
10
+ if let StatementKind::Function { name, parameters, body } = &stmt.kind {
11
+ functions_table.add_function(FunctionDef {
12
+ name: name.clone(),
13
+ parameters: parameters.clone(),
14
+ body: body.clone(),
15
+ });
16
+
17
+ return Some(functions_table.clone());
18
+ }
19
+
20
+ None
21
+ }
@@ -9,7 +9,7 @@ pub fn interprete_load_statement(
9
9
  variable_table: &mut VariableTable
10
10
  ) -> Option<VariableTable> {
11
11
  if let StatementKind::Load { source, alias } = &stmt.kind {
12
- variable_table.set(alias.to_string(), Value::String(source.clone()));
12
+ variable_table.set(alias.to_string(), Value::Sample(source.clone()));
13
13
 
14
14
  return Some(variable_table.clone());
15
15
  }