@devaloop/devalang 0.0.1-alpha.9 → 0.0.1-beta.1

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 (271) hide show
  1. package/.cargo/config.toml +2 -0
  2. package/.devalang +10 -4
  3. package/.github/workflows/ci.yml +103 -0
  4. package/Cargo.toml +80 -48
  5. package/README.md +135 -154
  6. package/docs/CHANGELOG.md +386 -1
  7. package/docs/CONTRIBUTING.md +101 -0
  8. package/docs/ROADMAP.md +10 -7
  9. package/docs/TODO.md +21 -9
  10. package/examples/automation.deva +42 -0
  11. package/examples/bank.deva +7 -0
  12. package/examples/duration.deva +9 -0
  13. package/examples/events.deva +12 -0
  14. package/examples/function.deva +15 -0
  15. package/examples/index.deva +57 -12
  16. package/examples/loop.deva +5 -12
  17. package/examples/pattern.deva +8 -0
  18. package/examples/plugin.deva +16 -0
  19. package/examples/variables.deva +1 -1
  20. package/out-tsc/bin/index.d.ts +2 -0
  21. package/out-tsc/bin/index.js +51 -7
  22. package/out-tsc/core/functions/index.d.ts +37 -0
  23. package/out-tsc/core/functions/index.js +76 -0
  24. package/out-tsc/core/index.d.ts +6 -0
  25. package/out-tsc/core/index.js +22 -0
  26. package/out-tsc/core/types/index.d.ts +4 -0
  27. package/out-tsc/core/types/index.js +20 -0
  28. package/out-tsc/core/types/plugin.d.ts +18 -0
  29. package/out-tsc/core/types/plugin.js +2 -0
  30. package/out-tsc/core/types/result.d.ts +27 -0
  31. package/out-tsc/core/types/result.js +2 -0
  32. package/out-tsc/core/types/statement.d.ts +106 -0
  33. package/out-tsc/core/types/statement.js +2 -0
  34. package/out-tsc/core/types/value.d.ts +43 -0
  35. package/out-tsc/core/types/value.js +2 -0
  36. package/out-tsc/index.d.ts +7 -0
  37. package/out-tsc/index.js +42 -1
  38. package/out-tsc/pkg/devalang_core.d.ts +13 -0
  39. package/out-tsc/pkg/devalang_core.js +50 -0
  40. package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +33 -0
  41. package/out-tsc/scripts/copy-wasm-dts.d.ts +1 -0
  42. package/out-tsc/scripts/copy-wasm-dts.js +73 -0
  43. package/out-tsc/scripts/postinstall.d.ts +1 -0
  44. package/out-tsc/scripts/postinstall.js +83 -0
  45. package/out-tsc/scripts/version/bump.d.ts +1 -0
  46. package/out-tsc/scripts/version/fetch.d.ts +1 -0
  47. package/out-tsc/scripts/version/index.d.ts +1 -0
  48. package/out-tsc/scripts/version/sync.d.ts +1 -0
  49. package/package.json +28 -7
  50. package/project-version.json +4 -4
  51. package/rust/cli/bank/api.rs +122 -0
  52. package/rust/cli/bank/commands.rs +275 -0
  53. package/rust/cli/bank/mod.rs +29 -0
  54. package/rust/cli/build/commands.rs +103 -0
  55. package/rust/cli/build/mod.rs +2 -0
  56. package/rust/cli/build/process.rs +146 -0
  57. package/rust/cli/check/mod.rs +208 -0
  58. package/rust/cli/discover/commands.rs +253 -0
  59. package/rust/cli/discover/config.rs +111 -0
  60. package/rust/cli/discover/fs.rs +19 -0
  61. package/rust/cli/discover/install.rs +103 -0
  62. package/rust/cli/discover/metadata.rs +48 -0
  63. package/rust/cli/discover/mod.rs +5 -0
  64. package/rust/cli/{init.rs → init/commands.rs} +32 -23
  65. package/rust/cli/init/mod.rs +1 -0
  66. package/rust/cli/install/addon.rs +118 -0
  67. package/rust/cli/install/bank.rs +53 -0
  68. package/rust/cli/install/commands.rs +35 -0
  69. package/rust/cli/install/mod.rs +4 -0
  70. package/rust/cli/install/plugin.rs +61 -0
  71. package/rust/cli/login/commands.rs +124 -0
  72. package/rust/cli/login/mod.rs +1 -0
  73. package/rust/cli/mod.rs +12 -205
  74. package/rust/cli/parser.rs +314 -0
  75. package/rust/cli/play/commands.rs +324 -0
  76. package/rust/cli/play/io.rs +17 -0
  77. package/rust/cli/play/mod.rs +5 -0
  78. package/rust/cli/play/process.rs +150 -0
  79. package/rust/cli/play/realtime.rs +91 -0
  80. package/rust/cli/play/utils.rs +23 -0
  81. package/rust/cli/telemetry/commands.rs +22 -0
  82. package/rust/cli/telemetry/event_creator.rs +80 -0
  83. package/rust/cli/telemetry/mod.rs +3 -0
  84. package/rust/cli/telemetry/send.rs +51 -0
  85. package/rust/cli/{template.rs → template/commands.rs} +69 -57
  86. package/rust/cli/template/mod.rs +1 -0
  87. package/rust/cli/update/commands.rs +6 -0
  88. package/rust/cli/update/mod.rs +1 -0
  89. package/rust/config/driver.rs +103 -0
  90. package/rust/config/mod.rs +3 -16
  91. package/rust/config/ops.rs +26 -0
  92. package/rust/config/settings.rs +101 -0
  93. package/rust/core/audio/engine/helpers.rs +170 -0
  94. package/rust/core/audio/engine/mod.rs +7 -0
  95. package/rust/core/audio/engine/sample.rs +366 -0
  96. package/rust/core/audio/engine/synth.rs +325 -0
  97. package/rust/core/audio/evaluator.rs +310 -31
  98. package/rust/core/audio/interpreter/arrow_call.rs +311 -129
  99. package/rust/core/audio/interpreter/automate.rs +18 -0
  100. package/rust/core/audio/interpreter/call.rs +294 -64
  101. package/rust/core/audio/interpreter/condition.rs +71 -69
  102. package/rust/core/audio/interpreter/driver.rs +542 -216
  103. package/rust/core/audio/interpreter/function.rs +26 -0
  104. package/rust/core/audio/interpreter/let_.rs +38 -19
  105. package/rust/core/audio/interpreter/load.rs +19 -18
  106. package/rust/core/audio/interpreter/loop_.rs +114 -67
  107. package/rust/core/audio/interpreter/mod.rs +14 -12
  108. package/rust/core/audio/interpreter/sleep.rs +28 -36
  109. package/rust/core/audio/interpreter/spawn.rs +252 -66
  110. package/rust/core/audio/interpreter/tempo.rs +40 -16
  111. package/rust/core/audio/interpreter/trigger.rs +239 -69
  112. package/rust/core/audio/loader/mod.rs +1 -1
  113. package/rust/core/audio/loader/trigger.rs +97 -52
  114. package/rust/core/audio/mod.rs +7 -6
  115. package/rust/core/audio/player.rs +70 -54
  116. package/rust/core/audio/renderer.rs +54 -54
  117. package/rust/core/audio/special/easing.rs +189 -0
  118. package/rust/core/audio/special/env.rs +45 -0
  119. package/rust/core/audio/special/math.rs +134 -0
  120. package/rust/core/audio/special/mod.rs +9 -0
  121. package/rust/core/audio/special/modulator.rs +143 -0
  122. package/rust/core/builder/mod.rs +86 -80
  123. package/rust/core/debugger/lexer.rs +27 -27
  124. package/rust/core/debugger/mod.rs +30 -21
  125. package/rust/core/debugger/module.rs +55 -0
  126. package/rust/core/debugger/preprocessor.rs +27 -27
  127. package/rust/core/debugger/store.rs +40 -25
  128. package/rust/core/error/mod.rs +269 -60
  129. package/rust/core/lexer/driver.rs +61 -0
  130. package/rust/core/lexer/handler/arrow.rs +82 -31
  131. package/rust/core/lexer/handler/at.rs +21 -21
  132. package/rust/core/lexer/handler/brace.rs +41 -41
  133. package/rust/core/lexer/handler/colon.rs +21 -21
  134. package/rust/core/lexer/handler/comment.rs +30 -30
  135. package/rust/core/lexer/handler/dot.rs +21 -21
  136. package/rust/core/lexer/handler/driver.rs +337 -226
  137. package/rust/core/lexer/handler/identifier.rs +47 -41
  138. package/rust/core/lexer/handler/indent.rs +66 -52
  139. package/rust/core/lexer/handler/mod.rs +15 -14
  140. package/rust/core/lexer/handler/newline.rs +23 -23
  141. package/rust/core/lexer/handler/number.rs +31 -31
  142. package/rust/core/lexer/handler/operator.rs +46 -44
  143. package/rust/core/lexer/handler/parenthesis.rs +41 -0
  144. package/rust/core/lexer/handler/slash.rs +21 -0
  145. package/rust/core/lexer/handler/string.rs +63 -63
  146. package/rust/core/lexer/mod.rs +3 -51
  147. package/rust/core/lexer/token.rs +17 -12
  148. package/rust/core/mod.rs +10 -10
  149. package/rust/core/parser/driver.rs +584 -331
  150. package/rust/core/parser/handler/arrow_call.rs +253 -126
  151. package/rust/core/parser/handler/at.rs +279 -162
  152. package/rust/core/parser/handler/bank.rs +104 -41
  153. package/rust/core/parser/handler/condition.rs +83 -74
  154. package/rust/core/parser/handler/dot.rs +148 -112
  155. package/rust/core/parser/handler/identifier/automate.rs +254 -0
  156. package/rust/core/parser/handler/identifier/call.rs +91 -41
  157. package/rust/core/parser/handler/identifier/emit.rs +70 -0
  158. package/rust/core/parser/handler/identifier/function.rs +113 -0
  159. package/rust/core/parser/handler/identifier/group.rs +89 -75
  160. package/rust/core/parser/handler/identifier/let_.rs +173 -133
  161. package/rust/core/parser/handler/identifier/mod.rs +55 -51
  162. package/rust/core/parser/handler/identifier/on.rs +107 -0
  163. package/rust/core/parser/handler/identifier/print.rs +49 -0
  164. package/rust/core/parser/handler/identifier/sleep.rs +43 -33
  165. package/rust/core/parser/handler/identifier/spawn.rs +91 -41
  166. package/rust/core/parser/handler/identifier/synth.rs +135 -65
  167. package/rust/core/parser/handler/loop_.rs +194 -72
  168. package/rust/core/parser/handler/mod.rs +9 -8
  169. package/rust/core/parser/handler/pattern.rs +74 -0
  170. package/rust/core/parser/handler/tempo.rs +57 -47
  171. package/rust/core/parser/mod.rs +3 -4
  172. package/rust/core/parser/statement.rs +11 -96
  173. package/rust/core/plugin/loader.rs +137 -0
  174. package/rust/core/plugin/mod.rs +2 -0
  175. package/rust/core/plugin/runner.rs +347 -0
  176. package/rust/core/preprocessor/loader.rs +637 -193
  177. package/rust/core/preprocessor/mod.rs +4 -4
  178. package/rust/core/preprocessor/module.rs +60 -50
  179. package/rust/core/preprocessor/processor.rs +114 -76
  180. package/rust/core/preprocessor/resolver/bank.rs +49 -47
  181. package/rust/core/preprocessor/resolver/call.rs +124 -123
  182. package/rust/core/preprocessor/resolver/condition.rs +95 -92
  183. package/rust/core/preprocessor/resolver/driver.rs +324 -227
  184. package/rust/core/preprocessor/resolver/function.rs +69 -0
  185. package/rust/core/preprocessor/resolver/group.rs +94 -61
  186. package/rust/core/preprocessor/resolver/let_.rs +32 -31
  187. package/rust/core/preprocessor/resolver/loop_.rs +318 -91
  188. package/rust/core/preprocessor/resolver/mod.rs +16 -14
  189. package/rust/core/preprocessor/resolver/pattern.rs +83 -0
  190. package/rust/core/preprocessor/resolver/spawn.rs +99 -58
  191. package/rust/core/preprocessor/resolver/synth.rs +54 -50
  192. package/rust/core/preprocessor/resolver/tempo.rs +48 -49
  193. package/rust/core/preprocessor/resolver/trigger.rs +116 -112
  194. package/rust/core/preprocessor/resolver/value.rs +176 -78
  195. package/rust/core/store/export.rs +28 -28
  196. package/rust/core/store/function.rs +40 -0
  197. package/rust/core/store/global.rs +61 -39
  198. package/rust/core/store/import.rs +28 -28
  199. package/rust/core/store/mod.rs +5 -4
  200. package/rust/core/store/variable.rs +51 -28
  201. package/rust/core/utils/mod.rs +1 -2
  202. package/rust/core/utils/path.rs +37 -31
  203. package/rust/lib.rs +308 -117
  204. package/rust/main.rs +364 -65
  205. package/rust/types/Cargo.toml +11 -0
  206. package/rust/types/src/addons.rs +55 -0
  207. package/rust/types/src/ast.rs +202 -0
  208. package/rust/types/src/config.rs +74 -0
  209. package/rust/types/src/lib.rs +12 -0
  210. package/rust/types/src/telemetry.rs +85 -0
  211. package/rust/utils/Cargo.toml +26 -0
  212. package/rust/utils/src/error.rs +186 -0
  213. package/rust/utils/src/file.rs +94 -0
  214. package/rust/utils/src/first_usage.rs +97 -0
  215. package/rust/utils/{mod.rs → src/lib.rs} +9 -6
  216. package/rust/utils/{logger.rs → src/logger.rs} +200 -123
  217. package/rust/utils/src/path.rs +88 -0
  218. package/rust/utils/src/signature.rs +41 -0
  219. package/rust/utils/{spinner.rs → src/spinner.rs} +20 -21
  220. package/rust/utils/src/version.rs +27 -0
  221. package/rust/utils/{watcher.rs → src/watcher.rs} +46 -33
  222. package/rust/web/api.rs +5 -0
  223. package/rust/web/cdn.rs +34 -0
  224. package/rust/web/mod.rs +3 -0
  225. package/rust/web/sso.rs +5 -0
  226. package/templates/minimal/README.md +143 -127
  227. package/templates/welcome/README.md +143 -127
  228. package/templates/welcome/src/index.deva +56 -8
  229. package/templates/welcome/src/variables.deva +2 -4
  230. package/tests/integration.rs +21 -0
  231. package/tests/rust/cli_check_build.rs +21 -0
  232. package/tests/rust/cli_help.rs +12 -0
  233. package/tests/rust/cli_template_list.rs +10 -0
  234. package/tests/rust/cli_version.rs +11 -0
  235. package/tests/typescript/index.spec.ts +136 -0
  236. package/tests/typescript/playhead.spec.ts +36 -0
  237. package/tests/typescript/render_e2e.spec.ts +77 -0
  238. package/tsconfig.json +12 -10
  239. package/typescript/bin/index.ts +19 -5
  240. package/typescript/core/functions/index.ts +83 -0
  241. package/typescript/core/index.ts +6 -0
  242. package/typescript/core/types/index.ts +4 -0
  243. package/typescript/core/types/plugin.ts +19 -0
  244. package/typescript/core/types/result.ts +29 -0
  245. package/typescript/core/types/statement.ts +47 -0
  246. package/typescript/core/types/value.ts +29 -0
  247. package/typescript/index.ts +8 -1
  248. package/typescript/pkg/devalang_core.d.ts +4 -0
  249. package/typescript/pkg/devalang_core.ts +49 -0
  250. package/typescript/scripts/copy-wasm-dts.ts +41 -0
  251. package/typescript/scripts/postinstall.ts +85 -0
  252. package/typescript/scripts/version/bump.ts +0 -1
  253. package/typescript/scripts/version/index.ts +0 -1
  254. package/docs/COMMANDS.md +0 -85
  255. package/docs/CONFIG.md +0 -30
  256. package/docs/SYNTAX.md +0 -210
  257. package/out-tsc/bin/devalang.exe +0 -0
  258. package/out-tsc/scripts/postbuild.js +0 -11
  259. package/rust/cli/build.rs +0 -137
  260. package/rust/cli/check.rs +0 -117
  261. package/rust/cli/play.rs +0 -193
  262. package/rust/config/loader.rs +0 -13
  263. package/rust/core/audio/engine.rs +0 -203
  264. package/rust/core/shared/duration.rs +0 -8
  265. package/rust/core/shared/mod.rs +0 -2
  266. package/rust/core/shared/value.rs +0 -18
  267. package/rust/core/utils/validation.rs +0 -37
  268. package/rust/utils/file.rs +0 -35
  269. package/rust/utils/signature.rs +0 -17
  270. package/rust/utils/version.rs +0 -15
  271. package/typescript/scripts/postbuild.ts +0 -8
@@ -1,64 +1,294 @@
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,
6
- };
7
-
8
- pub fn interprete_call_statement(
9
- stmt: &Statement,
10
- audio_engine: AudioEngine,
11
- variable_table: VariableTable,
12
- base_bpm: f32,
13
- base_duration: f32,
14
- max_end_time: f32,
15
- cursor_time: f32
16
- ) -> (AudioEngine, f32, f32) {
17
- match &stmt.value {
18
- Value::String(identifier) | Value::Identifier(identifier) => {
19
- if let Some(Value::Map(map)) = variable_table.clone().get(identifier) {
20
- if let Some(Value::Block(block)) = map.get("body") {
21
- let (eng, _, end_time) = execute_audio_block(
22
- audio_engine,
23
- variable_table,
24
- block.clone(),
25
- base_bpm,
26
- base_duration,
27
- max_end_time,
28
- cursor_time
29
- );
30
-
31
- return (eng, max_end_time.max(end_time), end_time);
32
- } else {
33
- eprintln!("❌ Group '{}' has no 'body' block", identifier);
34
- }
35
- } else {
36
- eprintln!("❌ Group '{}' not found or not a map", identifier);
37
- }
38
- }
39
-
40
- Value::Map(map) => {
41
- if let Some(Value::Block(block)) = map.get("body") {
42
- let (eng, _, end_time) = execute_audio_block(
43
- audio_engine,
44
- variable_table,
45
- block.clone(),
46
- base_bpm,
47
- base_duration,
48
- max_end_time,
49
- cursor_time
50
- );
51
-
52
- return (eng, max_end_time.max(end_time), end_time);
53
- } else {
54
- eprintln!("❌ Call map has no 'body' block");
55
- }
56
- }
57
-
58
- other => {
59
- eprintln!("❌ Invalid call statement: expected identifier or map, found {:?}", other);
60
- }
61
- }
62
-
63
- (audio_engine, max_end_time, cursor_time)
64
- }
1
+ use devalang_types::{Duration, Value};
2
+
3
+ use crate::core::{
4
+ audio::{engine::AudioEngine, interpreter::driver::execute_audio_block},
5
+ parser::statement::{Statement, StatementKind},
6
+ store::{function::FunctionTable, global::GlobalStore, variable::VariableTable},
7
+ };
8
+
9
+ pub fn interprete_call_statement(
10
+ stmt: &Statement,
11
+ audio_engine: &mut AudioEngine,
12
+ variable_table: &VariableTable,
13
+ functions: &FunctionTable,
14
+ global_store: &GlobalStore,
15
+ base_bpm: f32,
16
+ base_duration: f32,
17
+ max_end_time: f32,
18
+ cursor_time: f32,
19
+ ) -> (f32, f32) {
20
+ if let StatementKind::Call { name, args } = &stmt.kind {
21
+ // Classic function call case
22
+ if let Some(func) = functions.functions.get(name) {
23
+ // function found
24
+ if func.parameters.len() != args.len() {
25
+ eprintln!(
26
+ "❌ Function '{}' expects {} args, got {}",
27
+ name,
28
+ func.parameters.len(),
29
+ args.len()
30
+ );
31
+ return (max_end_time, cursor_time);
32
+ }
33
+
34
+ let mut local_vars = VariableTable::with_parent(variable_table.clone());
35
+ for (param, arg) in func.parameters.iter().zip(args) {
36
+ local_vars.set(param.clone(), arg.clone());
37
+ }
38
+
39
+ return execute_audio_block(
40
+ audio_engine,
41
+ global_store,
42
+ local_vars,
43
+ functions.clone(),
44
+ &func.body,
45
+ base_bpm,
46
+ base_duration,
47
+ max_end_time,
48
+ cursor_time,
49
+ );
50
+ }
51
+
52
+ // Group case
53
+ if let Some(group_stmt) = find_group(name, variable_table, global_store) {
54
+ // group found
55
+ if let Value::Map(map) = &group_stmt.value {
56
+ if let Some(Value::Block(body)) = map.get("body") {
57
+ return execute_audio_block(
58
+ audio_engine,
59
+ global_store,
60
+ variable_table.clone(),
61
+ functions.clone(),
62
+ body,
63
+ base_bpm,
64
+ base_duration,
65
+ max_end_time,
66
+ cursor_time,
67
+ );
68
+ }
69
+ }
70
+ }
71
+
72
+ // Pattern case
73
+ if let Some(pattern_stmt) = find_pattern(name, variable_table, global_store) {
74
+ // Extract pattern string from statement value
75
+ if let Value::String(pat) = &pattern_stmt.value {
76
+ // Determine target entity (explicit or inferred)
77
+ let mut target_entity = name.clone();
78
+ if let StatementKind::Pattern { name: _n, target } = &pattern_stmt.kind {
79
+ if let Some(t) = target {
80
+ target_entity = t.clone();
81
+ }
82
+ }
83
+
84
+ // Build a variable table snapshot for resolution like triggers do
85
+ // Preserve the full parent chain so lookups behave the same as runtime
86
+ fn clone_with_parents(
87
+ orig: &crate::core::store::variable::VariableTable,
88
+ ) -> crate::core::store::variable::VariableTable {
89
+ crate::core::store::variable::VariableTable {
90
+ variables: orig.variables.clone(),
91
+ parent: orig
92
+ .parent
93
+ .as_ref()
94
+ .map(|p| Box::new(clone_with_parents(p))),
95
+ }
96
+ }
97
+
98
+ let final_variable_table = clone_with_parents(variable_table);
99
+
100
+ // Normalize pattern: remove spaces and line breaks
101
+ let pattern_str: String = pat.chars().filter(|c| !c.is_whitespace()).collect();
102
+ if pattern_str.is_empty() {
103
+ return (max_end_time, cursor_time);
104
+ }
105
+
106
+ let step_count = pattern_str.len() as f32;
107
+ // Assume pattern spans one bar (4 beats)
108
+ let total_bar = 4.0 * base_duration;
109
+ let step_duration = total_bar / step_count; // seconds per step
110
+
111
+ let mut updated_max = max_end_time;
112
+
113
+ for (i, ch) in pattern_str.chars().enumerate() {
114
+ if ch == '-' {
115
+ continue; // rest
116
+ }
117
+
118
+ // Schedule a trigger at cursor_time + offset
119
+ let event_time = cursor_time + (i as f32) * step_duration;
120
+
121
+ // Resolve trigger value similarly to interprete_trigger_statement
122
+ let mut trigger_val = Value::String(target_entity.clone());
123
+ if let Some(val) = variable_table.variables.get(&target_entity) {
124
+ match val {
125
+ Value::Identifier(id) => {
126
+ // resolve from parent if available
127
+ if let Some(parent) = &variable_table.parent {
128
+ if let Some(v) = parent.get(id) {
129
+ trigger_val = v.clone();
130
+ }
131
+ } else if let Some(v) = variable_table.get(id) {
132
+ trigger_val = v.clone();
133
+ }
134
+ }
135
+ Value::Map(map) => {
136
+ if let Some(Value::String(src)) = map.get("entity") {
137
+ trigger_val = Value::String(src.clone());
138
+ } else if let Some(Value::Identifier(src)) = map.get("entity") {
139
+ trigger_val = Value::Identifier(src.clone());
140
+ }
141
+ }
142
+ Value::Sample(sample_src) => {
143
+ trigger_val = Value::Sample(sample_src.clone());
144
+ }
145
+ _ => {
146
+ // leave as string
147
+ }
148
+ }
149
+ }
150
+
151
+ // Use loader to get sample path and sample length
152
+ let (src, sample_length) = crate::core::audio::loader::trigger::load_trigger(
153
+ &trigger_val,
154
+ &Duration::Number(step_duration),
155
+ &None,
156
+ base_duration,
157
+ final_variable_table.clone(),
158
+ );
159
+
160
+ let play_length = step_duration.min(sample_length);
161
+
162
+ let trigger_src = match trigger_val.get("entity") {
163
+ Some(Value::String(s)) => s.clone(),
164
+ Some(Value::Identifier(id)) => id.clone(),
165
+ Some(Value::Statement(stmt)) => {
166
+ if let StatementKind::Trigger { entity, .. } = &stmt.kind {
167
+ entity.clone()
168
+ } else {
169
+ src.clone()
170
+ }
171
+ }
172
+ _ => src.clone(),
173
+ };
174
+
175
+ audio_engine.insert_sample(
176
+ &trigger_src,
177
+ event_time,
178
+ play_length,
179
+ None,
180
+ &final_variable_table,
181
+ );
182
+
183
+ let end_time = event_time + play_length;
184
+ if end_time > updated_max {
185
+ updated_max = end_time;
186
+ }
187
+ }
188
+
189
+ return (updated_max, cursor_time);
190
+ }
191
+ }
192
+
193
+ // Function or group not found; keep as debug-free fail path
194
+ }
195
+
196
+ (max_end_time, cursor_time)
197
+ }
198
+
199
+ fn find_group(
200
+ name: &str,
201
+ variable_table: &VariableTable,
202
+ global_store: &GlobalStore,
203
+ ) -> Option<Statement> {
204
+ use crate::core::parser::statement::Statement;
205
+ use crate::core::parser::statement::StatementKind;
206
+
207
+ if let Some(Value::Statement(stmt_box)) = variable_table.get(name) {
208
+ if let StatementKind::Group = stmt_box.kind {
209
+ return Some(*stmt_box.clone());
210
+ }
211
+ }
212
+
213
+ if let Some(val) = global_store.variables.variables.get(name) {
214
+ match val {
215
+ Value::Statement(stmt_box) => {
216
+ if let StatementKind::Group = stmt_box.kind {
217
+ return Some(*stmt_box.clone());
218
+ }
219
+ }
220
+ Value::Map(map) => {
221
+ // Try to rebuild a Group statement from the stored map
222
+ if let (Some(Value::String(_id)), Some(Value::Block(_body))) =
223
+ (map.get("identifier"), map.get("body"))
224
+ {
225
+ let stmt = Statement {
226
+ kind: StatementKind::Group,
227
+ value: Value::Map(map.clone()),
228
+ indent: 0,
229
+ line: 0,
230
+ column: 0,
231
+ };
232
+ return Some(stmt);
233
+ }
234
+ }
235
+ _ => {}
236
+ }
237
+ }
238
+
239
+ None
240
+ }
241
+
242
+ fn find_pattern(
243
+ name: &str,
244
+ variable_table: &VariableTable,
245
+ global_store: &GlobalStore,
246
+ ) -> Option<Statement> {
247
+ use crate::core::parser::statement::Statement;
248
+ use crate::core::parser::statement::StatementKind;
249
+
250
+ if let Some(Value::Statement(stmt_box)) = variable_table.get(name) {
251
+ if let StatementKind::Pattern { .. } = stmt_box.kind {
252
+ return Some(*stmt_box.clone());
253
+ }
254
+ }
255
+
256
+ if let Some(val) = global_store.variables.variables.get(name) {
257
+ match val {
258
+ Value::Statement(stmt_box) => {
259
+ if let StatementKind::Pattern { .. } = stmt_box.kind {
260
+ return Some(*stmt_box.clone());
261
+ }
262
+ }
263
+ Value::Map(map) => {
264
+ if let Some(Value::String(_pat)) = map.get("pattern") {
265
+ // Rebuild a Pattern statement from stored map if possible
266
+ let stmt = Statement {
267
+ kind: StatementKind::Pattern {
268
+ name: name.to_string(),
269
+ target: map.get("target").and_then(|v| match v {
270
+ Value::String(s) => Some(s.clone()),
271
+ _ => None,
272
+ }),
273
+ },
274
+ value: Value::String(
275
+ map.get("pattern")
276
+ .and_then(|v| match v {
277
+ Value::String(s) => Some(s.clone()),
278
+ _ => None,
279
+ })
280
+ .unwrap_or_default(),
281
+ ),
282
+ indent: 0,
283
+ line: 0,
284
+ column: 0,
285
+ };
286
+ return Some(stmt);
287
+ }
288
+ }
289
+ _ => {}
290
+ }
291
+ }
292
+
293
+ None
294
+ }
@@ -1,69 +1,71 @@
1
- use crate::core::{
2
- audio::{
3
- engine::AudioEngine,
4
- evaluator::evaluate_condition_string,
5
- interpreter::driver::execute_audio_block,
6
- },
7
- parser::statement::Statement,
8
- shared::value::Value,
9
- store::variable::VariableTable,
10
- };
11
-
12
- pub fn interprete_condition_statement(
13
- stmt: &Statement,
14
- audio_engine: AudioEngine,
15
- variable_table: VariableTable,
16
- base_bpm: f32,
17
- base_duration: f32,
18
- max_end_time: f32,
19
- cursor_time: f32
20
- ) -> (AudioEngine, f32, f32) {
21
- let mut engine = audio_engine.clone();
22
- let mut vars = variable_table.clone();
23
- let mut cur_time = cursor_time;
24
- let mut max_time = max_end_time;
25
-
26
- let mut current = stmt.value.clone();
27
-
28
- loop {
29
- let Value::Map(map) = current else {
30
- break;
31
- };
32
-
33
- let should_execute = match map.get("condition") {
34
- Some(Value::Boolean(b)) => *b,
35
- Some(Value::String(expr)) => evaluate_condition_string(expr, &vars),
36
- Some(_) => false,
37
- None => true,
38
- };
39
-
40
- if should_execute {
41
- if let Some(Value::Block(block)) = map.get("body") {
42
- let (new_engine, _, new_max) = execute_audio_block(
43
- engine,
44
- vars,
45
- block.clone(),
46
- base_bpm,
47
- base_duration,
48
- max_time,
49
- cur_time
50
- );
51
- return (new_engine, new_max, new_max);
52
- } else {
53
- break;
54
- }
55
- }
56
-
57
- // Advance to the next condition
58
- match map.get("next") {
59
- Some(Value::Map(next_map)) => {
60
- current = Value::Map(next_map.clone());
61
- }
62
- _ => {
63
- break;
64
- }
65
- }
66
- }
67
-
68
- (audio_engine, max_end_time, cursor_time)
69
- }
1
+ use devalang_types::Value;
2
+
3
+ use crate::core::{
4
+ audio::{
5
+ engine::AudioEngine, evaluator::evaluate_condition_string,
6
+ interpreter::driver::execute_audio_block,
7
+ },
8
+ parser::statement::Statement,
9
+ store::{function::FunctionTable, global::GlobalStore, variable::VariableTable},
10
+ };
11
+
12
+ pub fn interprete_condition_statement(
13
+ stmt: &Statement,
14
+ audio_engine: &mut AudioEngine,
15
+ global_store: &GlobalStore,
16
+ variable_table: &VariableTable,
17
+ functions_table: &FunctionTable,
18
+ base_bpm: f32,
19
+ base_duration: f32,
20
+ max_end_time: f32,
21
+ cursor_time: f32,
22
+ ) -> (f32, f32) {
23
+ let cur_time = cursor_time;
24
+ let max_time = max_end_time;
25
+
26
+ let mut current = stmt.value.clone();
27
+
28
+ loop {
29
+ let Value::Map(map) = current else {
30
+ break;
31
+ };
32
+
33
+ let should_execute = match map.get("condition") {
34
+ Some(Value::Boolean(b)) => *b,
35
+ Some(Value::String(expr)) => evaluate_condition_string(expr, &variable_table.clone()),
36
+ Some(_) => false,
37
+ None => true,
38
+ };
39
+
40
+ if should_execute {
41
+ if let Some(Value::Block(block)) = map.get("body") {
42
+ let (new_max, cursor_time) = execute_audio_block(
43
+ audio_engine,
44
+ global_store,
45
+ variable_table.clone(),
46
+ functions_table.clone(),
47
+ block,
48
+ base_bpm,
49
+ base_duration,
50
+ max_time,
51
+ cur_time,
52
+ );
53
+ return (new_max, cursor_time);
54
+ } else {
55
+ break;
56
+ }
57
+ }
58
+
59
+ // Advance to the next condition
60
+ match map.get("next") {
61
+ Some(Value::Map(next_map)) => {
62
+ current = Value::Map(next_map.clone());
63
+ }
64
+ _ => {
65
+ break;
66
+ }
67
+ }
68
+ }
69
+
70
+ (max_end_time, cursor_time)
71
+ }