@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.
- package/.devalang +8 -9
- package/Cargo.toml +8 -3
- package/README.md +36 -34
- package/docs/CHANGELOG.md +65 -1
- package/docs/CONTRIBUTING.md +1 -0
- package/docs/ROADMAP.md +2 -2
- package/docs/TODO.md +6 -5
- package/examples/bank.deva +2 -4
- package/examples/function.deva +15 -0
- package/examples/index.deva +25 -14
- package/out-tsc/bin/devalang.exe +0 -0
- package/package.json +6 -6
- package/project-version.json +3 -3
- package/rust/cli/bank.rs +2 -1
- package/rust/cli/build.rs +76 -14
- package/rust/cli/check.rs +71 -8
- package/rust/cli/driver.rs +40 -28
- package/rust/cli/install.rs +22 -7
- package/rust/cli/login.rs +134 -0
- package/rust/cli/mod.rs +2 -1
- package/rust/cli/play.rs +45 -20
- package/rust/common/api.rs +8 -0
- package/rust/common/cdn.rs +2 -5
- package/rust/common/mod.rs +3 -1
- package/rust/common/sso.rs +8 -0
- package/rust/config/driver.rs +19 -1
- package/rust/config/loader.rs +56 -10
- package/rust/core/audio/engine.rs +254 -91
- package/rust/core/audio/interpreter/arrow_call.rs +34 -15
- 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 +90 -128
- 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/builder/mod.rs +11 -6
- 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/indent.rs +16 -2
- package/rust/core/lexer/handler/mod.rs +1 -0
- package/rust/core/lexer/handler/parenthesis.rs +41 -0
- package/rust/core/lexer/token.rs +4 -0
- package/rust/core/mod.rs +2 -1
- package/rust/core/parser/driver.rs +47 -4
- package/rust/core/parser/handler/arrow_call.rs +78 -18
- package/rust/core/parser/handler/bank.rs +35 -7
- package/rust/core/parser/handler/dot.rs +81 -123
- 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/plugin/loader.rs +48 -0
- package/rust/core/plugin/mod.rs +1 -0
- package/rust/core/preprocessor/loader.rs +50 -32
- 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/installer/addon.rs +80 -0
- package/rust/installer/bank.rs +24 -14
- package/rust/installer/mod.rs +4 -1
- package/rust/installer/plugin.rs +55 -0
- package/rust/lib.rs +10 -7
- package/rust/main.rs +32 -9
- package/rust/utils/logger.rs +16 -0
- package/rust/utils/mod.rs +45 -1
- 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::
|
|
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
|
-
|
|
57
|
-
|
|
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
|
|
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
|
|
66
|
-
if let Some(
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
)
|
|
88
|
+
// Note parameters and calculations
|
|
89
|
+
let amp_note = extract_f32(¬e_params, "amp", base_bpm).unwrap_or(amp);
|
|
90
|
+
let duration_ms = extract_f32(¬e_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(¬e_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
|
-
|
|
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::{
|
|
3
|
-
parser::statement::{
|
|
4
|
-
shared::
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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 (
|
|
39
|
-
}
|
|
40
|
-
|
|
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
|
-
|
|
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
|
-
|
|
52
|
-
|
|
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
|
-
|
|
65
|
-
|
|
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
|
-
(
|
|
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
|
-
|
|
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
|
-
) -> (
|
|
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, &
|
|
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 (
|
|
43
|
-
|
|
44
|
-
|
|
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 (
|
|
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
|
-
(
|
|
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
|
-
|
|
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,65 @@ 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
|
-
|
|
53
|
+
audio_engine: &mut AudioEngine,
|
|
54
|
+
global_store: &GlobalStore,
|
|
61
55
|
mut variable_table: VariableTable,
|
|
62
|
-
mut
|
|
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
|
-
) -> (
|
|
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
|
-
if
|
|
74
|
-
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
97
|
+
audio_engine,
|
|
134
98
|
&variable_table,
|
|
135
|
-
base_bpm,
|
|
136
99
|
base_duration,
|
|
137
|
-
|
|
100
|
+
cursor_time,
|
|
138
101
|
max_end_time
|
|
139
102
|
)
|
|
140
103
|
{
|
|
141
|
-
|
|
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 (
|
|
118
|
+
let (new_max, new_cursor) = interprete_loop_statement(
|
|
174
119
|
&stmt,
|
|
175
|
-
audio_engine
|
|
176
|
-
|
|
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
|
-
|
|
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
|
|
191
|
-
variable_table
|
|
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 (
|
|
148
|
+
let (new_max, new_cursor) = interprete_call_arrow_statement(
|
|
205
149
|
&stmt,
|
|
206
|
-
|
|
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 =
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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
|
-
|
|
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
|
-
(
|
|
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::
|
|
12
|
+
variable_table.set(alias.to_string(), Value::Sample(source.clone()));
|
|
13
13
|
|
|
14
14
|
return Some(variable_table.clone());
|
|
15
15
|
}
|