@devaloop/devalang 0.0.1-alpha.11 → 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 (66) hide show
  1. package/.devalang +8 -8
  2. package/Cargo.toml +8 -8
  3. package/README.md +1 -14
  4. package/docs/CHANGELOG.md +44 -0
  5. package/docs/TODO.md +1 -1
  6. package/examples/index.deva +10 -11
  7. package/out-tsc/bin/devalang.exe +0 -0
  8. package/package.json +2 -1
  9. package/project-version.json +3 -3
  10. package/rust/cli/build.rs +25 -2
  11. package/rust/cli/check.rs +26 -3
  12. package/rust/cli/play.rs +1 -1
  13. package/rust/core/audio/engine.rs +207 -41
  14. package/rust/core/audio/interpreter/call.rs +72 -47
  15. package/rust/core/audio/interpreter/condition.rs +14 -12
  16. package/rust/core/audio/interpreter/driver.rs +84 -127
  17. package/rust/core/audio/interpreter/function.rs +21 -0
  18. package/rust/core/audio/interpreter/load.rs +1 -1
  19. package/rust/core/audio/interpreter/loop_.rs +24 -18
  20. package/rust/core/audio/interpreter/mod.rs +2 -1
  21. package/rust/core/audio/interpreter/sleep.rs +0 -6
  22. package/rust/core/audio/interpreter/spawn.rs +78 -60
  23. package/rust/core/audio/interpreter/trigger.rs +169 -61
  24. package/rust/core/audio/loader/trigger.rs +37 -4
  25. package/rust/core/audio/player.rs +20 -10
  26. package/rust/core/audio/renderer.rs +24 -25
  27. package/rust/core/debugger/mod.rs +2 -0
  28. package/rust/core/debugger/module.rs +47 -0
  29. package/rust/core/debugger/store.rs +25 -11
  30. package/rust/core/error/mod.rs +6 -0
  31. package/rust/core/lexer/handler/driver.rs +23 -1
  32. package/rust/core/lexer/handler/identifier.rs +1 -0
  33. package/rust/core/lexer/handler/mod.rs +1 -0
  34. package/rust/core/lexer/handler/parenthesis.rs +41 -0
  35. package/rust/core/lexer/token.rs +3 -0
  36. package/rust/core/parser/driver.rs +31 -3
  37. package/rust/core/parser/handler/dot.rs +65 -129
  38. package/rust/core/parser/handler/identifier/call.rs +69 -22
  39. package/rust/core/parser/handler/identifier/function.rs +92 -0
  40. package/rust/core/parser/handler/identifier/let_.rs +13 -19
  41. package/rust/core/parser/handler/identifier/mod.rs +1 -0
  42. package/rust/core/parser/handler/identifier/spawn.rs +74 -27
  43. package/rust/core/parser/statement.rs +16 -4
  44. package/rust/core/preprocessor/loader.rs +45 -29
  45. package/rust/core/preprocessor/module.rs +3 -1
  46. package/rust/core/preprocessor/processor.rs +26 -1
  47. package/rust/core/preprocessor/resolver/call.rs +61 -84
  48. package/rust/core/preprocessor/resolver/condition.rs +11 -6
  49. package/rust/core/preprocessor/resolver/driver.rs +52 -6
  50. package/rust/core/preprocessor/resolver/function.rs +78 -0
  51. package/rust/core/preprocessor/resolver/group.rs +43 -13
  52. package/rust/core/preprocessor/resolver/let_.rs +7 -10
  53. package/rust/core/preprocessor/resolver/mod.rs +2 -1
  54. package/rust/core/preprocessor/resolver/spawn.rs +64 -30
  55. package/rust/core/preprocessor/resolver/trigger.rs +7 -3
  56. package/rust/core/preprocessor/resolver/value.rs +10 -1
  57. package/rust/core/shared/value.rs +4 -1
  58. package/rust/core/store/function.rs +34 -0
  59. package/rust/core/store/global.rs +9 -10
  60. package/rust/core/store/mod.rs +2 -1
  61. package/rust/core/store/variable.rs +6 -0
  62. package/rust/installer/bank.rs +1 -1
  63. package/rust/installer/mod.rs +2 -1
  64. package/rust/lib.rs +10 -8
  65. package/rust/utils/mod.rs +44 -1
  66. /package/rust/{utils/installer.rs → installer/utils.rs} +0 -0
@@ -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
+ // 1. Cas : fonction classique
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
+ // 2. Cas : group dans le scope local OU global
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,64 @@ 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,
61
- mut variable_table: VariableTable,
62
- mut statements: Vec<Statement>,
53
+ audio_engine: &mut AudioEngine,
54
+ global_store: &GlobalStore,
55
+ variable_table: VariableTable,
56
+ 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
71
  if
74
- let Some(new_variable_table) = interprete_load_statement(
72
+ let Some(new_table) = interprete_load_statement(
75
73
  &stmt,
76
- &mut variable_table
74
+ &mut variable_table.clone()
77
75
  )
78
76
  {
79
- variable_table = new_variable_table;
80
- } else {
81
- eprintln!("❌ Failed to interpret load statement: {:?}", stmt);
77
+ // Extend the variable_table if necessary
82
78
  }
83
79
  }
84
-
85
80
  StatementKind::Let { .. } => {
86
- if
87
- let Some(new_variable_table) = interprete_let_statement(
88
- &stmt,
89
- &mut variable_table
90
- )
91
- {
92
- variable_table = new_variable_table;
93
- } else {
94
- eprintln!("❌ Failed to interpret let statement: {:?}", stmt);
95
- }
81
+ interprete_let_statement(&stmt, &mut variable_table.clone());
82
+ }
83
+ StatementKind::Function { .. } => {
84
+ interprete_function_statement(&stmt, &mut functions_table.clone());
96
85
  }
97
-
98
86
  StatementKind::Tempo => {
99
87
  if let Some((new_bpm, new_duration)) = interprete_tempo_statement(&stmt) {
100
88
  base_bpm = new_bpm;
101
89
  base_duration = new_duration;
102
- } else {
103
- eprintln!("❌ Failed to interpret tempo statement: {:?}", stmt);
104
90
  }
105
91
  }
106
-
107
92
  StatementKind::Trigger { .. } => {
108
93
  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(
94
+ let Some((new_cursor, new_max, _)) = interprete_trigger_statement(
132
95
  &stmt,
133
- temp_engine,
96
+ audio_engine,
134
97
  &variable_table,
135
- base_bpm,
136
98
  base_duration,
137
- initial_cursor_time,
99
+ cursor_time,
138
100
  max_end_time
139
101
  )
140
102
  {
141
- audio_engine.merge_with(updated_engine);
103
+ cursor_time = new_cursor;
104
+ max_end_time = new_max;
142
105
  }
143
106
  }
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
107
  StatementKind::Sleep => {
163
108
  let (new_cursor, new_max) = interprete_sleep_statement(
164
109
  &stmt,
@@ -168,42 +113,40 @@ pub fn execute_audio_block(
168
113
  cursor_time = new_cursor;
169
114
  max_end_time = new_max;
170
115
  }
171
-
172
116
  StatementKind::Loop => {
173
- let (loop_engine, new_max, new_cursor) = interprete_loop_statement(
117
+ let (new_max, new_cursor) = interprete_loop_statement(
174
118
  &stmt,
175
- audio_engine.clone(),
176
- variable_table.clone(),
119
+ audio_engine,
120
+ global_store,
121
+ &variable_table,
122
+ &functions_table,
177
123
  base_bpm,
178
124
  base_duration,
179
125
  max_end_time,
180
126
  cursor_time
181
127
  );
182
- audio_engine = loop_engine;
183
128
  cursor_time = new_cursor;
184
129
  max_end_time = new_max;
185
130
  }
186
-
187
- StatementKind::If | StatementKind::ElseIf | StatementKind::Else => {
188
- let (condition_engine, new_max, new_cursor) = interprete_condition_statement(
131
+ StatementKind::Call { .. } => {
132
+ let (new_max, new_cursor) = interprete_call_statement(
189
133
  &stmt,
190
- audio_engine.clone(),
191
- variable_table.clone(),
134
+ audio_engine,
135
+ &variable_table,
136
+ &functions_table,
137
+ global_store,
192
138
  base_bpm,
193
139
  base_duration,
194
140
  max_end_time,
195
- cursor_time
141
+ cursor_time,
196
142
  );
197
-
198
- audio_engine = condition_engine;
199
143
  cursor_time = new_cursor;
200
144
  max_end_time = new_max;
201
145
  }
202
-
203
146
  StatementKind::ArrowCall { .. } => {
204
- let (new_max_end_time, new_cursor_time) = interprete_call_arrow_statement(
147
+ let (new_max, new_cursor) = interprete_call_arrow_statement(
205
148
  &stmt,
206
- &mut audio_engine,
149
+ audio_engine,
207
150
  &variable_table,
208
151
  base_bpm,
209
152
  base_duration,
@@ -211,26 +154,40 @@ pub fn execute_audio_block(
211
154
  Some(&mut cursor_time),
212
155
  true
213
156
  );
214
-
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);
157
+ cursor_time = new_cursor;
158
+ max_end_time = new_max;
229
159
  }
160
+ _ => {}
230
161
  }
231
162
  }
232
163
 
233
- audio_engine.set_variables(variable_table);
164
+ // Execute parallel spawns (collect results)
165
+ let spawn_results: Vec<(AudioEngine, f32)> = spawns
166
+ .par_iter()
167
+ .map(|stmt| {
168
+ let mut local_engine = AudioEngine::new(audio_engine.module_name.clone());
169
+ let (spawn_max, _) = interprete_spawn_statement(
170
+ stmt,
171
+ &mut local_engine,
172
+ &variable_table,
173
+ &functions_table,
174
+ global_store,
175
+ base_bpm,
176
+ base_duration,
177
+ 0.0,
178
+ 0.0
179
+ );
180
+ (local_engine, spawn_max)
181
+ })
182
+ .collect();
183
+
184
+ // Finally, merge results from all spawns
185
+ for (local_engine, spawn_max) in spawn_results {
186
+ audio_engine.merge_with(local_engine);
187
+ if spawn_max > max_end_time {
188
+ max_end_time = spawn_max;
189
+ }
190
+ }
234
191
 
235
- (audio_engine, base_bpm, max_end_time)
192
+ (max_end_time.max(cursor_time), cursor_time)
236
193
  }
@@ -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
  }
@@ -2,18 +2,20 @@ use crate::core::{
2
2
  audio::{ engine::AudioEngine, interpreter::driver::execute_audio_block },
3
3
  parser::statement::{ Statement, StatementKind },
4
4
  shared::{ duration::Duration, value::Value },
5
- store::variable::VariableTable,
5
+ store::{function::FunctionTable, global::GlobalStore, variable::VariableTable},
6
6
  };
7
7
 
8
8
  pub fn interprete_loop_statement(
9
9
  stmt: &Statement,
10
- audio_engine: AudioEngine,
11
- variable_table: VariableTable,
10
+ audio_engine: &mut AudioEngine,
11
+ global_store: &GlobalStore,
12
+ variable_table: &VariableTable,
13
+ functions_table: &FunctionTable,
12
14
  base_bpm: f32,
13
15
  base_duration: f32,
14
16
  max_end_time: f32,
15
17
  cursor_time: f32
16
- ) -> (AudioEngine, f32, f32) {
18
+ ) -> (f32, f32) {
17
19
  if let Value::Map(loop_value) = &stmt.value {
18
20
  let loop_count = match loop_value.get("iterator") {
19
21
  Some(Value::Number(n)) => *n as usize,
@@ -22,12 +24,15 @@ pub fn interprete_loop_statement(
22
24
  *n as usize
23
25
  } else {
24
26
  eprintln!("❌ Loop iterator must be a number, found: {:?}", ident);
25
- return (audio_engine, max_end_time, cursor_time);
27
+ return (max_end_time, cursor_time);
26
28
  }
27
29
  }
28
30
  _ => {
29
- eprintln!("❌ Loop iterator must be a number, found: {:?}", loop_value.get("iterator"));
30
- return (audio_engine, max_end_time, cursor_time);
31
+ eprintln!(
32
+ "❌ Loop iterator must be a number, found: {:?}",
33
+ loop_value.get("iterator")
34
+ );
35
+ return (max_end_time, cursor_time);
31
36
  }
32
37
  };
33
38
 
@@ -35,7 +40,7 @@ pub fn interprete_loop_statement(
35
40
  Some(Value::Block(body)) => body.clone(),
36
41
  _ => {
37
42
  eprintln!("❌ Loop body must be a block, found: {:?}", loop_value.get("body"));
38
- return (audio_engine, max_end_time, cursor_time);
43
+ return (max_end_time, cursor_time);
39
44
  }
40
45
  };
41
46
 
@@ -43,10 +48,12 @@ pub fn interprete_loop_statement(
43
48
  let mut cur_time = cursor_time;
44
49
  let mut max_time = max_end_time;
45
50
 
46
- for _ in 0..loop_count {
47
- let (eng, _, end_time) = execute_audio_block(
48
- engine,
51
+ for i in 0..loop_count {
52
+ let (block_end_time, cursor_time) = execute_audio_block(
53
+ &mut engine,
54
+ global_store,
49
55
  variable_table.clone(),
56
+ functions_table.clone(),
50
57
  loop_body.clone(),
51
58
  base_bpm,
52
59
  base_duration,
@@ -54,14 +61,13 @@ pub fn interprete_loop_statement(
54
61
  cur_time
55
62
  );
56
63
 
57
- engine = eng;
58
- cur_time = end_time;
59
- max_time = max_time.max(end_time);
64
+ cur_time = block_end_time;
65
+ max_time = max_time.max(cur_time);
60
66
  }
61
67
 
62
- (engine, max_time, cur_time)
63
- } else {
64
- eprintln!("❌ Loop statement value is not a map");
65
- (audio_engine, max_end_time, cursor_time)
68
+ return (max_time, cur_time);
66
69
  }
70
+
71
+ eprintln!("❌ Loop statement value is not a map");
72
+ (max_end_time, cursor_time)
67
73
  }
@@ -9,4 +9,5 @@ pub mod sleep;
9
9
  pub mod loop_;
10
10
  pub mod call;
11
11
  pub mod condition;
12
- pub mod arrow_call;
12
+ pub mod arrow_call;
13
+ pub mod function;
@@ -18,12 +18,6 @@ pub fn interprete_sleep_statement(
18
18
  0.0
19
19
  })
20
20
  }
21
- Value::String(s) if s.ends_with("s") => {
22
- s.trim_end_matches("s").parse::<f32>().unwrap_or_else(|_| {
23
- eprintln!("❌ Invalid sleep value (s): {}", s);
24
- 0.0
25
- })
26
- }
27
21
  other => {
28
22
  eprintln!("❌ Invalid sleep value: {:?}", other);
29
23
  0.0