@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.
- package/Cargo.toml +54 -53
- package/README.md +1 -14
- package/docs/CHANGELOG.md +26 -0
- package/docs/TODO.md +1 -1
- package/examples/index.deva +10 -13
- package/out-tsc/bin/devalang.exe +0 -0
- package/package.json +1 -1
- package/project-version.json +3 -3
- package/rust/cli/build.rs +25 -2
- package/rust/cli/check.rs +26 -3
- package/rust/cli/play.rs +1 -1
- package/rust/core/audio/engine.rs +126 -73
- package/rust/core/audio/interpreter/call.rs +72 -47
- package/rust/core/audio/interpreter/condition.rs +14 -12
- package/rust/core/audio/interpreter/driver.rs +84 -127
- package/rust/core/audio/interpreter/function.rs +21 -0
- package/rust/core/audio/interpreter/load.rs +1 -1
- package/rust/core/audio/interpreter/loop_.rs +24 -18
- package/rust/core/audio/interpreter/mod.rs +2 -1
- package/rust/core/audio/interpreter/sleep.rs +0 -6
- package/rust/core/audio/interpreter/spawn.rs +78 -60
- package/rust/core/audio/interpreter/trigger.rs +157 -70
- package/rust/core/audio/loader/trigger.rs +37 -4
- package/rust/core/audio/player.rs +20 -10
- package/rust/core/audio/renderer.rs +24 -25
- package/rust/core/debugger/mod.rs +2 -0
- package/rust/core/debugger/module.rs +47 -0
- package/rust/core/debugger/store.rs +25 -11
- package/rust/core/error/mod.rs +6 -0
- package/rust/core/lexer/handler/driver.rs +23 -1
- package/rust/core/lexer/handler/identifier.rs +1 -0
- package/rust/core/lexer/handler/mod.rs +1 -0
- package/rust/core/lexer/handler/parenthesis.rs +41 -0
- package/rust/core/lexer/token.rs +3 -0
- package/rust/core/parser/driver.rs +3 -1
- package/rust/core/parser/handler/dot.rs +64 -127
- package/rust/core/parser/handler/identifier/call.rs +69 -22
- package/rust/core/parser/handler/identifier/function.rs +92 -0
- package/rust/core/parser/handler/identifier/let_.rs +13 -19
- package/rust/core/parser/handler/identifier/mod.rs +1 -0
- package/rust/core/parser/handler/identifier/spawn.rs +74 -27
- package/rust/core/parser/statement.rs +16 -4
- package/rust/core/preprocessor/loader.rs +45 -29
- package/rust/core/preprocessor/module.rs +3 -1
- package/rust/core/preprocessor/processor.rs +26 -1
- package/rust/core/preprocessor/resolver/call.rs +61 -84
- package/rust/core/preprocessor/resolver/condition.rs +11 -6
- package/rust/core/preprocessor/resolver/driver.rs +52 -6
- package/rust/core/preprocessor/resolver/function.rs +78 -0
- package/rust/core/preprocessor/resolver/group.rs +43 -13
- package/rust/core/preprocessor/resolver/let_.rs +7 -10
- package/rust/core/preprocessor/resolver/mod.rs +2 -1
- package/rust/core/preprocessor/resolver/spawn.rs +64 -30
- package/rust/core/preprocessor/resolver/trigger.rs +7 -3
- package/rust/core/preprocessor/resolver/value.rs +10 -1
- package/rust/core/shared/value.rs +4 -1
- package/rust/core/store/function.rs +34 -0
- package/rust/core/store/global.rs +9 -10
- package/rust/core/store/mod.rs +2 -1
- package/rust/core/store/variable.rs +6 -0
- package/rust/lib.rs +10 -7
- package/rust/utils/mod.rs +45 -1
|
@@ -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
|
-
|
|
27
|
+
audio_engine: &mut AudioEngine,
|
|
24
28
|
entry: String,
|
|
25
|
-
output: String
|
|
26
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
(
|
|
49
|
+
(max_end_time, cursor_time)
|
|
57
50
|
}
|
|
58
51
|
|
|
59
52
|
pub fn execute_audio_block(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
) -> (
|
|
68
|
-
let
|
|
62
|
+
) -> (f32, f32) {
|
|
63
|
+
let (spawns, others): (Vec<_>, Vec<_>) = statements
|
|
64
|
+
.into_iter()
|
|
65
|
+
.partition(|stmt| matches!(stmt.kind, StatementKind::Spawn { .. }));
|
|
69
66
|
|
|
70
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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((
|
|
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
|
-
|
|
96
|
+
audio_engine,
|
|
134
97
|
&variable_table,
|
|
135
|
-
base_bpm,
|
|
136
98
|
base_duration,
|
|
137
|
-
|
|
99
|
+
cursor_time,
|
|
138
100
|
max_end_time
|
|
139
101
|
)
|
|
140
102
|
{
|
|
141
|
-
|
|
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 (
|
|
117
|
+
let (new_max, new_cursor) = interprete_loop_statement(
|
|
174
118
|
&stmt,
|
|
175
|
-
audio_engine
|
|
176
|
-
|
|
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
|
-
|
|
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
|
|
191
|
-
variable_table
|
|
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 (
|
|
147
|
+
let (new_max, new_cursor) = interprete_call_arrow_statement(
|
|
205
148
|
&stmt,
|
|
206
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
(
|
|
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::
|
|
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
|
-
|
|
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
|
-
) -> (
|
|
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 (
|
|
27
|
+
return (max_end_time, cursor_time);
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
_ => {
|
|
29
|
-
eprintln!(
|
|
30
|
-
|
|
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 (
|
|
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
|
|
47
|
-
let (
|
|
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
|
-
|
|
58
|
-
|
|
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
|
-
(
|
|
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
|
}
|
|
@@ -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
|
|
@@ -1,84 +1,102 @@
|
|
|
1
1
|
use crate::core::{
|
|
2
|
-
audio::{
|
|
3
|
-
parser::statement::Statement,
|
|
2
|
+
audio::{engine::AudioEngine, interpreter::driver::execute_audio_block},
|
|
3
|
+
parser::statement::{Statement, StatementKind},
|
|
4
4
|
shared::value::Value,
|
|
5
|
-
store::variable::VariableTable,
|
|
5
|
+
store::{function::FunctionTable, global::GlobalStore, variable::VariableTable},
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
pub fn interprete_spawn_statement(
|
|
9
9
|
stmt: &Statement,
|
|
10
|
-
audio_engine: AudioEngine,
|
|
10
|
+
audio_engine: &mut AudioEngine,
|
|
11
11
|
variable_table: &VariableTable,
|
|
12
|
+
functions: &FunctionTable,
|
|
13
|
+
global_store: &GlobalStore,
|
|
12
14
|
base_bpm: f32,
|
|
13
15
|
base_duration: f32,
|
|
16
|
+
max_end_time: f32,
|
|
14
17
|
cursor_time: f32,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
) -> (f32, f32) {
|
|
19
|
+
match &stmt.kind {
|
|
20
|
+
StatementKind::Spawn { name, args } => {
|
|
21
|
+
let mut local_engine = AudioEngine::new(audio_engine.module_name.clone());
|
|
22
|
+
|
|
23
|
+
// ✅ 1. Cas : fonction
|
|
24
|
+
if let Some(func) = functions.functions.get(name) {
|
|
25
|
+
if func.parameters.len() != args.len() {
|
|
26
|
+
eprintln!(
|
|
27
|
+
"❌ Function '{}' expects {} args, got {}",
|
|
28
|
+
name,
|
|
29
|
+
func.parameters.len(),
|
|
30
|
+
args.len()
|
|
31
|
+
);
|
|
32
|
+
return (max_end_time, cursor_time);
|
|
33
|
+
}
|
|
29
34
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
let mut local_vars = VariableTable::with_parent(variable_table.clone());
|
|
36
|
+
for (param, arg) in func.parameters.iter().zip(args) {
|
|
37
|
+
local_vars.set(param.clone(), arg.clone());
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let (spawn_max, _) = execute_audio_block(
|
|
41
|
+
&mut local_engine,
|
|
42
|
+
global_store,
|
|
43
|
+
local_vars,
|
|
44
|
+
functions.clone(),
|
|
45
|
+
func.body.clone(),
|
|
36
46
|
base_bpm,
|
|
37
47
|
base_duration,
|
|
38
|
-
|
|
39
|
-
|
|
48
|
+
0.0,
|
|
49
|
+
0.0,
|
|
40
50
|
);
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
51
|
+
|
|
52
|
+
audio_engine.merge_with(local_engine);
|
|
53
|
+
return (spawn_max.max(max_end_time), cursor_time);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ✅ 2. Cas : group dans variable_table ou global_store
|
|
57
|
+
if let Some(group_stmt) = find_group(name, variable_table, global_store) {
|
|
58
|
+
if let Value::Map(map) = &group_stmt.value {
|
|
59
|
+
if let Some(Value::Block(body)) = map.get("body") {
|
|
60
|
+
let (spawn_max, _) = execute_audio_block(
|
|
61
|
+
&mut local_engine,
|
|
62
|
+
global_store,
|
|
63
|
+
variable_table.clone(),
|
|
64
|
+
functions.clone(),
|
|
65
|
+
body.clone(),
|
|
66
|
+
base_bpm,
|
|
67
|
+
base_duration,
|
|
68
|
+
0.0,
|
|
69
|
+
0.0,
|
|
70
|
+
);
|
|
71
|
+
audio_engine.merge_with(local_engine);
|
|
72
|
+
return (spawn_max.max(max_end_time), cursor_time);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
44
75
|
}
|
|
45
|
-
None
|
|
46
|
-
}
|
|
47
76
|
|
|
48
|
-
|
|
49
|
-
eprintln!("❌ Invalid spawn statement: expected identifier, found {:?}", stmt.value);
|
|
50
|
-
None
|
|
77
|
+
eprintln!("❌ Function or group '{}' not found", name);
|
|
51
78
|
}
|
|
79
|
+
|
|
80
|
+
_ => eprintln!("❌ interprete_spawn_statement expected Spawn, got {:?}", stmt.kind),
|
|
52
81
|
}
|
|
82
|
+
|
|
83
|
+
(max_end_time, cursor_time)
|
|
53
84
|
}
|
|
54
85
|
|
|
55
|
-
fn
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
variable_table.clone(),
|
|
69
|
-
block.clone(),
|
|
70
|
-
base_bpm,
|
|
71
|
-
base_duration,
|
|
72
|
-
max_end_time,
|
|
73
|
-
cursor_time
|
|
74
|
-
);
|
|
75
|
-
return Some((max_end_time.max(end_time), end_time, eng));
|
|
76
|
-
} else {
|
|
77
|
-
eprintln!("❌ Spawn group '{}' has no 'body' block", identifier);
|
|
86
|
+
fn find_group<'a>(
|
|
87
|
+
name: &str,
|
|
88
|
+
variable_table: &'a VariableTable,
|
|
89
|
+
global_store: &'a GlobalStore,
|
|
90
|
+
) -> Option<&'a Statement> {
|
|
91
|
+
if let Some(Value::Statement(stmt_box)) = variable_table.get(name) {
|
|
92
|
+
if let StatementKind::Group = stmt_box.kind {
|
|
93
|
+
return Some(stmt_box);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if let Some(Value::Statement(stmt_box)) = global_store.variables.variables.get(name) {
|
|
97
|
+
if let StatementKind::Group = stmt_box.kind {
|
|
98
|
+
return Some(stmt_box);
|
|
78
99
|
}
|
|
79
|
-
} else {
|
|
80
|
-
eprintln!("❌ Spawn group '{}' not found or not a map", identifier);
|
|
81
100
|
}
|
|
82
|
-
|
|
83
101
|
None
|
|
84
102
|
}
|