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

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 (322) hide show
  1. package/.cargo/config.toml +2 -0
  2. package/.devalang +6 -1
  3. package/.github/workflows/ci.yml +103 -0
  4. package/Cargo.toml +81 -48
  5. package/README.md +137 -154
  6. package/docs/CHANGELOG.md +428 -1
  7. package/docs/CONTRIBUTING.md +101 -0
  8. package/docs/ROADMAP.md +14 -7
  9. package/docs/TODO.md +16 -15
  10. package/examples/automation.deva +42 -0
  11. package/examples/bank.deva +7 -0
  12. package/examples/bus.deva +10 -0
  13. package/examples/duration.deva +9 -0
  14. package/examples/effect.deva +2 -0
  15. package/examples/events.deva +12 -0
  16. package/examples/filter.deva +11 -0
  17. package/examples/function.deva +15 -0
  18. package/examples/index.deva +57 -12
  19. package/examples/lfo.deva +9 -0
  20. package/examples/loop.deva +5 -12
  21. package/examples/pattern.deva +8 -0
  22. package/examples/plugin.deva +16 -0
  23. package/examples/synth.deva +11 -1
  24. package/examples/synth_types.deva +17 -0
  25. package/examples/variables.deva +1 -1
  26. package/out-tsc/bin/index.d.ts +2 -0
  27. package/out-tsc/bin/index.js +51 -7
  28. package/out-tsc/core/functions/index.d.ts +42 -0
  29. package/out-tsc/core/functions/index.js +87 -0
  30. package/out-tsc/core/index.d.ts +6 -0
  31. package/out-tsc/core/index.js +22 -0
  32. package/out-tsc/core/types/index.d.ts +4 -0
  33. package/out-tsc/core/types/index.js +20 -0
  34. package/out-tsc/core/types/plugin.d.ts +18 -0
  35. package/out-tsc/core/types/plugin.js +2 -0
  36. package/out-tsc/core/types/result.d.ts +27 -0
  37. package/out-tsc/core/types/result.js +2 -0
  38. package/out-tsc/core/types/statement.d.ts +106 -0
  39. package/out-tsc/core/types/statement.js +2 -0
  40. package/out-tsc/core/types/value.d.ts +43 -0
  41. package/out-tsc/core/types/value.js +2 -0
  42. package/out-tsc/index.d.ts +7 -0
  43. package/out-tsc/index.js +42 -1
  44. package/out-tsc/pkg/devalang_core.d.ts +15 -0
  45. package/out-tsc/pkg/devalang_core.js +65 -0
  46. package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +34 -0
  47. package/out-tsc/scripts/copy-wasm-dts.d.ts +1 -0
  48. package/out-tsc/scripts/copy-wasm-dts.js +73 -0
  49. package/out-tsc/scripts/postinstall.d.ts +1 -0
  50. package/out-tsc/scripts/postinstall.js +83 -0
  51. package/out-tsc/scripts/version/bump.d.ts +1 -0
  52. package/out-tsc/scripts/version/fetch.d.ts +1 -0
  53. package/out-tsc/scripts/version/index.d.ts +1 -0
  54. package/out-tsc/scripts/version/sync.d.ts +1 -0
  55. package/package.json +28 -7
  56. package/project-version.json +4 -4
  57. package/rust/cli/bank/api.rs +122 -0
  58. package/rust/cli/bank/commands.rs +306 -0
  59. package/rust/cli/bank/mod.rs +29 -0
  60. package/rust/cli/build/commands.rs +153 -0
  61. package/rust/cli/build/mod.rs +2 -0
  62. package/rust/cli/build/process.rs +165 -0
  63. package/rust/cli/check/mod.rs +208 -0
  64. package/rust/cli/discover/commands.rs +253 -0
  65. package/rust/cli/discover/config.rs +111 -0
  66. package/rust/cli/discover/fs.rs +19 -0
  67. package/rust/cli/discover/install.rs +103 -0
  68. package/rust/cli/discover/metadata.rs +48 -0
  69. package/rust/cli/discover/mod.rs +5 -0
  70. package/rust/cli/{init.rs → init/commands.rs} +32 -23
  71. package/rust/cli/init/mod.rs +1 -0
  72. package/rust/cli/install/addon.rs +118 -0
  73. package/rust/cli/install/bank.rs +72 -0
  74. package/rust/cli/install/commands.rs +35 -0
  75. package/rust/cli/install/mod.rs +4 -0
  76. package/rust/cli/install/plugin.rs +80 -0
  77. package/rust/cli/login/commands.rs +124 -0
  78. package/rust/cli/login/mod.rs +1 -0
  79. package/rust/cli/mod.rs +9 -202
  80. package/rust/cli/parser.rs +359 -0
  81. package/rust/cli/play/commands.rs +375 -0
  82. package/rust/cli/play/io.rs +17 -0
  83. package/rust/cli/play/mod.rs +5 -0
  84. package/rust/cli/play/process.rs +159 -0
  85. package/rust/cli/play/realtime.rs +91 -0
  86. package/rust/cli/play/utils.rs +23 -0
  87. package/rust/cli/telemetry/commands.rs +22 -0
  88. package/rust/cli/telemetry/event_creator.rs +80 -0
  89. package/rust/cli/telemetry/mod.rs +3 -0
  90. package/rust/cli/telemetry/send.rs +51 -0
  91. package/rust/cli/{template.rs → template/commands.rs} +17 -5
  92. package/rust/cli/template/mod.rs +1 -0
  93. package/rust/cli/update/commands.rs +6 -0
  94. package/rust/cli/update/mod.rs +1 -0
  95. package/rust/config/driver.rs +112 -0
  96. package/rust/config/mod.rs +3 -16
  97. package/rust/config/ops.rs +26 -0
  98. package/rust/config/settings.rs +101 -0
  99. package/rust/core/audio/engine/driver.rs +220 -0
  100. package/rust/core/audio/engine/export.rs +169 -0
  101. package/rust/core/audio/engine/helpers.rs +178 -0
  102. package/rust/core/audio/engine/mod.rs +56 -0
  103. package/rust/core/audio/engine/notes/dsp.rs +85 -0
  104. package/rust/core/audio/engine/notes/mod.rs +44 -0
  105. package/rust/core/audio/engine/notes/params.rs +294 -0
  106. package/rust/core/audio/engine/sample/insert.rs +199 -0
  107. package/rust/core/audio/engine/sample/mod.rs +40 -0
  108. package/rust/core/audio/engine/sample/padding.rs +170 -0
  109. package/rust/core/audio/evaluator/condition.rs +61 -0
  110. package/rust/core/audio/evaluator/mod.rs +9 -0
  111. package/rust/core/audio/evaluator/numeric.rs +152 -0
  112. package/rust/core/audio/evaluator/rhs.rs +16 -0
  113. package/rust/core/audio/evaluator/string_expr.rs +94 -0
  114. package/rust/core/audio/interpreter/driver.rs +574 -216
  115. package/rust/core/audio/interpreter/mod.rs +2 -12
  116. package/rust/core/audio/interpreter/statements/arrow_call/interprete.rs +175 -0
  117. package/rust/core/audio/interpreter/statements/arrow_call/methods/chord.rs +384 -0
  118. package/rust/core/audio/interpreter/statements/arrow_call/methods/mod.rs +2 -0
  119. package/rust/core/audio/interpreter/statements/arrow_call/methods/note.rs +316 -0
  120. package/rust/core/audio/interpreter/statements/arrow_call/mod.rs +3 -0
  121. package/rust/core/audio/interpreter/statements/arrow_call/types/arp.rs +192 -0
  122. package/rust/core/audio/interpreter/statements/arrow_call/types/mod.rs +24 -0
  123. package/rust/core/audio/interpreter/statements/arrow_call/types/pad.rs +116 -0
  124. package/rust/core/audio/interpreter/statements/arrow_call/types/pluck.rs +97 -0
  125. package/rust/core/audio/interpreter/statements/arrow_call/types/sub.rs +100 -0
  126. package/rust/core/audio/interpreter/statements/automate.rs +16 -0
  127. package/rust/core/audio/interpreter/statements/call.rs +295 -0
  128. package/rust/core/audio/interpreter/{condition.rs → statements/condition.rs} +72 -69
  129. package/rust/core/audio/interpreter/statements/function.rs +24 -0
  130. package/rust/core/audio/interpreter/statements/let_.rs +36 -0
  131. package/rust/core/audio/interpreter/statements/load.rs +17 -0
  132. package/rust/core/audio/interpreter/statements/loop_.rs +115 -0
  133. package/rust/core/audio/interpreter/statements/mod.rs +12 -0
  134. package/rust/core/audio/interpreter/statements/sleep.rs +28 -0
  135. package/rust/core/audio/interpreter/statements/spawn.rs +253 -0
  136. package/rust/core/audio/interpreter/statements/tempo.rs +40 -0
  137. package/rust/core/audio/interpreter/statements/trigger.rs +239 -0
  138. package/rust/core/audio/loader/mod.rs +1 -1
  139. package/rust/core/audio/loader/trigger.rs +98 -52
  140. package/rust/core/audio/mod.rs +2 -2
  141. package/rust/core/audio/player.rs +28 -12
  142. package/rust/core/audio/special/easing.rs +189 -0
  143. package/rust/core/audio/special/env.rs +45 -0
  144. package/rust/core/audio/special/math.rs +134 -0
  145. package/rust/core/audio/special/mod.rs +9 -0
  146. package/rust/core/audio/special/modulator.rs +143 -0
  147. package/rust/core/builder/mod.rs +129 -80
  148. package/rust/core/debugger/lexer.rs +4 -4
  149. package/rust/core/debugger/logs.rs +52 -0
  150. package/rust/core/debugger/mod.rs +11 -2
  151. package/rust/core/debugger/preprocessor.rs +4 -4
  152. package/rust/core/debugger/store.rs +38 -25
  153. package/rust/core/error/mod.rs +221 -12
  154. package/rust/core/lexer/driver.rs +59 -0
  155. package/rust/core/lexer/handler/arrow.rs +62 -11
  156. package/rust/core/lexer/handler/at.rs +5 -5
  157. package/rust/core/lexer/handler/brace.rs +11 -11
  158. package/rust/core/lexer/handler/colon.rs +5 -5
  159. package/rust/core/lexer/handler/comment.rs +3 -3
  160. package/rust/core/lexer/handler/dot.rs +6 -6
  161. package/rust/core/lexer/handler/driver.rs +143 -32
  162. package/rust/core/lexer/handler/identifier.rs +11 -5
  163. package/rust/core/lexer/handler/indent.rs +18 -4
  164. package/rust/core/lexer/handler/mod.rs +6 -5
  165. package/rust/core/lexer/handler/newline.rs +3 -3
  166. package/rust/core/lexer/handler/number.rs +5 -5
  167. package/rust/core/lexer/handler/operator.rs +5 -3
  168. package/rust/core/lexer/handler/parenthesis.rs +41 -0
  169. package/rust/core/lexer/handler/slash.rs +21 -0
  170. package/rust/core/lexer/handler/string.rs +3 -3
  171. package/rust/core/lexer/mod.rs +1 -49
  172. package/rust/core/lexer/token.rs +17 -12
  173. package/rust/core/mod.rs +9 -10
  174. package/rust/core/parser/driver/block.rs +111 -0
  175. package/rust/core/parser/driver/cursor.rs +82 -0
  176. package/rust/core/parser/driver/driver_impl.rs +139 -0
  177. package/rust/core/parser/driver/mod.rs +6 -0
  178. package/rust/core/parser/driver/parse_array.rs +120 -0
  179. package/rust/core/parser/driver/parse_map.rs +223 -0
  180. package/rust/core/parser/driver/parser.rs +160 -0
  181. package/rust/core/parser/handler/arrow_call.rs +277 -126
  182. package/rust/core/parser/handler/at.rs +142 -25
  183. package/rust/core/parser/handler/bank.rs +83 -20
  184. package/rust/core/parser/handler/condition.rs +14 -5
  185. package/rust/core/parser/handler/dot.rs +111 -75
  186. package/rust/core/parser/handler/identifier/automate.rs +254 -0
  187. package/rust/core/parser/handler/identifier/call.rs +74 -24
  188. package/rust/core/parser/handler/identifier/emit.rs +70 -0
  189. package/rust/core/parser/handler/identifier/function.rs +113 -0
  190. package/rust/core/parser/handler/identifier/group.rs +28 -14
  191. package/rust/core/parser/handler/identifier/let_.rs +61 -21
  192. package/rust/core/parser/handler/identifier/mod.rs +24 -20
  193. package/rust/core/parser/handler/identifier/on.rs +107 -0
  194. package/rust/core/parser/handler/identifier/print.rs +49 -0
  195. package/rust/core/parser/handler/identifier/sleep.rs +77 -14
  196. package/rust/core/parser/handler/identifier/spawn.rs +81 -31
  197. package/rust/core/parser/handler/identifier/synth.rs +102 -32
  198. package/rust/core/parser/handler/loop_.rs +144 -22
  199. package/rust/core/parser/handler/mod.rs +6 -5
  200. package/rust/core/parser/handler/pattern.rs +74 -0
  201. package/rust/core/parser/handler/tempo.rs +67 -9
  202. package/rust/core/parser/mod.rs +3 -4
  203. package/rust/core/parser/statement.rs +6 -92
  204. package/rust/core/plugin/loader.rs +137 -0
  205. package/rust/core/plugin/mod.rs +2 -0
  206. package/rust/core/plugin/runner/mod.rs +11 -0
  207. package/rust/core/plugin/runner/non_wasm.rs +297 -0
  208. package/rust/core/plugin/runner/wasm32.rs +43 -0
  209. package/rust/core/preprocessor/loader/inject.rs +278 -0
  210. package/rust/core/preprocessor/loader/loader_helpers.rs +110 -0
  211. package/rust/core/preprocessor/loader/mod.rs +235 -0
  212. package/rust/core/preprocessor/mod.rs +4 -4
  213. package/rust/core/preprocessor/module.rs +55 -50
  214. package/rust/core/preprocessor/processor/handlers.rs +107 -0
  215. package/rust/core/preprocessor/processor/mod.rs +1 -0
  216. package/rust/core/preprocessor/resolver/bank.rs +14 -12
  217. package/rust/core/preprocessor/resolver/call.rs +106 -105
  218. package/rust/core/preprocessor/resolver/condition.rs +13 -10
  219. package/rust/core/preprocessor/resolver/driver.rs +145 -48
  220. package/rust/core/preprocessor/resolver/function.rs +69 -0
  221. package/rust/core/preprocessor/resolver/group.rs +122 -61
  222. package/rust/core/preprocessor/resolver/let_.rs +13 -12
  223. package/rust/core/preprocessor/resolver/loop_.rs +240 -13
  224. package/rust/core/preprocessor/resolver/mod.rs +8 -6
  225. package/rust/core/preprocessor/resolver/pattern.rs +83 -0
  226. package/rust/core/preprocessor/resolver/spawn.rs +83 -42
  227. package/rust/core/preprocessor/resolver/synth.rs +15 -11
  228. package/rust/core/preprocessor/resolver/tempo.rs +13 -14
  229. package/rust/core/preprocessor/resolver/trigger.rs +32 -28
  230. package/rust/core/preprocessor/resolver/value.rs +111 -13
  231. package/rust/core/store/global.rs +57 -39
  232. package/rust/core/store/mod.rs +0 -3
  233. package/rust/lib.rs +323 -117
  234. package/rust/main.rs +388 -65
  235. package/rust/types/Cargo.toml +11 -0
  236. package/rust/types/src/addons.rs +55 -0
  237. package/rust/types/src/ast.rs +202 -0
  238. package/rust/types/src/config.rs +84 -0
  239. package/rust/types/src/lib.rs +15 -0
  240. package/rust/types/src/plugin.rs +20 -0
  241. package/rust/types/src/store.rs +139 -0
  242. package/rust/types/src/telemetry.rs +85 -0
  243. package/rust/utils/Cargo.toml +26 -0
  244. package/rust/utils/src/error.rs +186 -0
  245. package/rust/utils/src/file.rs +94 -0
  246. package/rust/utils/src/first_usage.rs +97 -0
  247. package/rust/utils/{mod.rs → src/lib.rs} +6 -3
  248. package/rust/utils/{logger.rs → src/logger.rs} +94 -17
  249. package/rust/utils/src/path.rs +129 -0
  250. package/rust/utils/src/signature.rs +41 -0
  251. package/rust/utils/{spinner.rs → src/spinner.rs} +7 -8
  252. package/rust/utils/src/version.rs +27 -0
  253. package/rust/utils/{watcher.rs → src/watcher.rs} +17 -4
  254. package/rust/web/api.rs +5 -0
  255. package/rust/web/cdn.rs +34 -0
  256. package/rust/web/mod.rs +3 -0
  257. package/rust/web/sso.rs +5 -0
  258. package/templates/minimal/README.md +143 -127
  259. package/templates/welcome/README.md +143 -127
  260. package/templates/welcome/src/index.deva +56 -8
  261. package/templates/welcome/src/variables.deva +2 -4
  262. package/tests/integration.rs +21 -0
  263. package/tests/rust/cli_check_build.rs +21 -0
  264. package/tests/rust/cli_help.rs +12 -0
  265. package/tests/rust/cli_template_list.rs +10 -0
  266. package/tests/rust/cli_version.rs +11 -0
  267. package/tests/typescript/index.spec.ts +136 -0
  268. package/tests/typescript/playhead.spec.ts +36 -0
  269. package/tests/typescript/render_e2e.spec.ts +77 -0
  270. package/tsconfig.json +12 -10
  271. package/typescript/bin/index.ts +19 -5
  272. package/typescript/core/functions/index.ts +94 -0
  273. package/typescript/core/index.ts +6 -0
  274. package/typescript/core/types/index.ts +4 -0
  275. package/typescript/core/types/plugin.ts +19 -0
  276. package/typescript/core/types/result.ts +29 -0
  277. package/typescript/core/types/statement.ts +47 -0
  278. package/typescript/core/types/value.ts +29 -0
  279. package/typescript/index.ts +8 -1
  280. package/typescript/pkg/devalang_core.d.ts +4 -0
  281. package/typescript/pkg/devalang_core.ts +65 -0
  282. package/typescript/scripts/copy-wasm-dts.ts +41 -0
  283. package/typescript/scripts/postinstall.ts +85 -0
  284. package/typescript/scripts/version/bump.ts +0 -1
  285. package/typescript/scripts/version/index.ts +0 -1
  286. package/docs/COMMANDS.md +0 -85
  287. package/docs/CONFIG.md +0 -30
  288. package/docs/SYNTAX.md +0 -210
  289. package/out-tsc/bin/devalang.exe +0 -0
  290. package/out-tsc/scripts/postbuild.js +0 -11
  291. package/rust/cli/build.rs +0 -137
  292. package/rust/cli/check.rs +0 -117
  293. package/rust/cli/play.rs +0 -193
  294. package/rust/config/loader.rs +0 -13
  295. package/rust/core/audio/engine.rs +0 -203
  296. package/rust/core/audio/evaluator.rs +0 -31
  297. package/rust/core/audio/interpreter/arrow_call.rs +0 -129
  298. package/rust/core/audio/interpreter/call.rs +0 -64
  299. package/rust/core/audio/interpreter/let_.rs +0 -19
  300. package/rust/core/audio/interpreter/load.rs +0 -18
  301. package/rust/core/audio/interpreter/loop_.rs +0 -67
  302. package/rust/core/audio/interpreter/sleep.rs +0 -36
  303. package/rust/core/audio/interpreter/spawn.rs +0 -66
  304. package/rust/core/audio/interpreter/tempo.rs +0 -16
  305. package/rust/core/audio/interpreter/trigger.rs +0 -69
  306. package/rust/core/audio/renderer.rs +0 -54
  307. package/rust/core/parser/driver.rs +0 -331
  308. package/rust/core/preprocessor/loader.rs +0 -193
  309. package/rust/core/preprocessor/processor.rs +0 -76
  310. package/rust/core/shared/duration.rs +0 -8
  311. package/rust/core/shared/mod.rs +0 -2
  312. package/rust/core/shared/value.rs +0 -18
  313. package/rust/core/store/export.rs +0 -28
  314. package/rust/core/store/import.rs +0 -28
  315. package/rust/core/store/variable.rs +0 -28
  316. package/rust/core/utils/mod.rs +0 -2
  317. package/rust/core/utils/path.rs +0 -31
  318. package/rust/core/utils/validation.rs +0 -37
  319. package/rust/utils/file.rs +0 -35
  320. package/rust/utils/signature.rs +0 -17
  321. package/rust/utils/version.rs +0 -15
  322. package/typescript/scripts/postbuild.ts +0 -8
@@ -0,0 +1,36 @@
1
+ use crate::core::parser::statement::{Statement, StatementKind};
2
+ use devalang_types::Value;
3
+ use devalang_types::store::VariableTable;
4
+
5
+ pub fn interprete_let_statement(
6
+ stmt: &Statement,
7
+ variable_table: &mut VariableTable,
8
+ ) -> Option<VariableTable> {
9
+ if let StatementKind::Let { name } = &stmt.kind {
10
+ // If RHS is a string and looks like an expression, evaluate it
11
+ let evaluated = match &stmt.value {
12
+ Value::String(s) if s.contains("$env") || s.contains("$math") => {
13
+ // We don't have direct env here; use defaults or infer from table
14
+ let bpm = if let Some(Value::Number(n)) = variable_table.get("bpm") {
15
+ *n
16
+ } else {
17
+ 120.0
18
+ };
19
+ // Try to infer beat from time-based variables if any, else 0.0
20
+ let beat = if let Some(Value::Number(n)) = variable_table.get("beat") {
21
+ *n
22
+ } else {
23
+ 0.0
24
+ };
25
+ crate::core::audio::evaluator::evaluate_rhs_into_value(s, variable_table, bpm, beat)
26
+ }
27
+ other => other.clone(),
28
+ };
29
+
30
+ variable_table.set(name.to_string(), evaluated);
31
+
32
+ return Some(variable_table.clone());
33
+ }
34
+
35
+ None
36
+ }
@@ -0,0 +1,17 @@
1
+ use devalang_types::Value;
2
+
3
+ use crate::core::parser::statement::{Statement, StatementKind};
4
+ use devalang_types::store::VariableTable;
5
+
6
+ pub fn interprete_load_statement(
7
+ stmt: &Statement,
8
+ variable_table: &mut VariableTable,
9
+ ) -> Option<VariableTable> {
10
+ if let StatementKind::Load { source, alias } = &stmt.kind {
11
+ variable_table.set(alias.to_string(), Value::Sample(source.clone()));
12
+
13
+ return Some(variable_table.clone());
14
+ }
15
+
16
+ None
17
+ }
@@ -0,0 +1,115 @@
1
+ use devalang_types::Value;
2
+
3
+ use crate::core::{
4
+ audio::{engine::AudioEngine, interpreter::driver::execute_audio_block},
5
+ parser::statement::Statement,
6
+ store::global::GlobalStore,
7
+ };
8
+ use devalang_types::store::{FunctionTable, VariableTable};
9
+
10
+ pub fn interprete_loop_statement(
11
+ stmt: &Statement,
12
+ audio_engine: &mut AudioEngine,
13
+ global_store: &GlobalStore,
14
+ variable_table: &VariableTable,
15
+ functions_table: &FunctionTable,
16
+ base_bpm: f32,
17
+ base_duration: f32,
18
+ max_end_time: f32,
19
+ cursor_time: f32,
20
+ ) -> (f32, f32) {
21
+ if let Value::Map(loop_value) = &stmt.value {
22
+ // Foreach form: { foreach: Identifier(name), array: Array([...]), body: Block }
23
+ if let (
24
+ Some(Value::Identifier(var_name)),
25
+ Some(Value::Array(items)),
26
+ Some(Value::Block(loop_body)),
27
+ ) = (
28
+ loop_value.get("foreach"),
29
+ loop_value.get("array"),
30
+ loop_value.get("body"),
31
+ ) {
32
+ let engine = audio_engine;
33
+ let mut cur_time = cursor_time;
34
+ let mut max_time = max_end_time;
35
+
36
+ for item in items {
37
+ let mut scoped_vars = variable_table.clone();
38
+ scoped_vars.set(var_name.clone(), item.clone());
39
+
40
+ let (block_end_time, new_cursor) = execute_audio_block(
41
+ engine,
42
+ global_store,
43
+ scoped_vars,
44
+ functions_table.clone(),
45
+ loop_body,
46
+ base_bpm,
47
+ base_duration,
48
+ max_time,
49
+ cur_time,
50
+ );
51
+
52
+ cur_time = new_cursor.max(block_end_time);
53
+ max_time = max_time.max(cur_time);
54
+ }
55
+
56
+ return (max_time, cur_time);
57
+ }
58
+
59
+ let loop_count = match loop_value.get("iterator") {
60
+ Some(Value::Number(n)) => *n as usize,
61
+ Some(Value::Identifier(ident)) => {
62
+ if let Some(Value::Number(n)) = variable_table.get(ident) {
63
+ *n as usize
64
+ } else {
65
+ eprintln!("❌ Loop iterator must be a number, found: {:?}", ident);
66
+ return (max_end_time, cursor_time);
67
+ }
68
+ }
69
+ _ => {
70
+ eprintln!(
71
+ "❌ Loop iterator must be a number, found: {:?}",
72
+ loop_value.get("iterator")
73
+ );
74
+ return (max_end_time, cursor_time);
75
+ }
76
+ };
77
+
78
+ let loop_body = match loop_value.get("body") {
79
+ Some(Value::Block(body)) => body.clone(),
80
+ _ => {
81
+ eprintln!(
82
+ "❌ Loop body must be a block, found: {:?}",
83
+ loop_value.get("body")
84
+ );
85
+ return (max_end_time, cursor_time);
86
+ }
87
+ };
88
+
89
+ let engine = audio_engine;
90
+ let mut cur_time = cursor_time;
91
+ let mut max_time = max_end_time;
92
+
93
+ for _ in 0..loop_count {
94
+ let (block_end_time, new_cursor) = execute_audio_block(
95
+ engine,
96
+ global_store,
97
+ variable_table.clone(),
98
+ functions_table.clone(),
99
+ &loop_body,
100
+ base_bpm,
101
+ base_duration,
102
+ max_time,
103
+ cur_time,
104
+ );
105
+
106
+ cur_time = new_cursor.max(block_end_time);
107
+ max_time = max_time.max(cur_time);
108
+ }
109
+
110
+ return (max_time, cur_time);
111
+ }
112
+
113
+ eprintln!("❌ Loop statement value is not a map");
114
+ (max_end_time, cursor_time)
115
+ }
@@ -0,0 +1,12 @@
1
+ pub mod arrow_call;
2
+ pub mod automate;
3
+ pub mod call;
4
+ pub mod condition;
5
+ pub mod function;
6
+ pub mod let_;
7
+ pub mod load;
8
+ pub mod loop_;
9
+ pub mod sleep;
10
+ pub mod spawn;
11
+ pub mod tempo;
12
+ pub mod trigger;
@@ -0,0 +1,28 @@
1
+ use crate::core::parser::statement::Statement;
2
+ use devalang_types::Value;
3
+
4
+ pub fn interprete_sleep_statement(
5
+ stmt: &Statement,
6
+ cursor_time: f32,
7
+ max_end_time: f32,
8
+ ) -> (f32, f32) {
9
+ let duration_secs = match &stmt.value {
10
+ Value::Number(ms) => *ms / 1000.0,
11
+ Value::String(s) if s.ends_with("ms") => s
12
+ .trim_end_matches("ms")
13
+ .parse::<f32>()
14
+ .map(|ms| ms / 1000.0)
15
+ .unwrap_or_else(|_| {
16
+ eprintln!("❌ Invalid sleep value (ms): {}", s);
17
+ 0.0
18
+ }),
19
+ other => {
20
+ eprintln!("❌ Invalid sleep value: {:?}", other);
21
+ 0.0
22
+ }
23
+ };
24
+
25
+ let new_cursor = cursor_time + duration_secs;
26
+ let new_max = max_end_time.max(new_cursor);
27
+ (new_cursor, new_max)
28
+ }
@@ -0,0 +1,253 @@
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::global::GlobalStore,
7
+ };
8
+ use devalang_types::store::{FunctionTable, VariableTable};
9
+
10
+ pub fn interprete_spawn_statement(
11
+ stmt: &Statement,
12
+ audio_engine: &mut AudioEngine,
13
+ variable_table: &VariableTable,
14
+ functions: &FunctionTable,
15
+ global_store: &GlobalStore,
16
+ base_bpm: f32,
17
+ base_duration: f32,
18
+ max_end_time: f32,
19
+ cursor_time: f32,
20
+ ) -> (f32, f32) {
21
+ if let StatementKind::Spawn { name, args } = &stmt.kind {
22
+ let mut local_engine = AudioEngine::new(audio_engine.module_name.clone());
23
+
24
+ // Function case
25
+ if let Some(func) = functions.functions.get(name) {
26
+ if func.parameters.len() != args.len() {
27
+ return (max_end_time, cursor_time);
28
+ }
29
+
30
+ let mut local_vars = VariableTable::with_parent(variable_table.clone());
31
+ for (param, arg) in func.parameters.iter().zip(args) {
32
+ local_vars.set(param.clone(), arg.clone());
33
+ }
34
+
35
+ let (spawn_max, _) = execute_audio_block(
36
+ &mut local_engine,
37
+ global_store,
38
+ local_vars,
39
+ functions.clone(),
40
+ &func.body,
41
+ base_bpm,
42
+ base_duration,
43
+ 0.0,
44
+ 0.0,
45
+ );
46
+
47
+ audio_engine.merge_with(local_engine);
48
+ return (spawn_max.max(max_end_time), cursor_time);
49
+ }
50
+
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
+ let (spawn_max, _) = execute_audio_block(
56
+ &mut local_engine,
57
+ global_store,
58
+ variable_table.clone(),
59
+ functions.clone(),
60
+ body,
61
+ base_bpm,
62
+ base_duration,
63
+ 0.0,
64
+ 0.0,
65
+ );
66
+ audio_engine.merge_with(local_engine);
67
+ return (spawn_max.max(max_end_time), cursor_time);
68
+ }
69
+ }
70
+ }
71
+
72
+ // Pattern case: allow spawning a pattern similar to call
73
+ if let Some(pattern_stmt) = find_pattern(name, variable_table, global_store) {
74
+ if let Value::String(pat) = &pattern_stmt.value {
75
+ let mut target_entity = name.clone();
76
+ if let StatementKind::Pattern { name: _n, target } = &pattern_stmt.kind {
77
+ if let Some(t) = target {
78
+ target_entity = t.clone();
79
+ }
80
+ }
81
+
82
+ let final_variable_table = if let Some(parent) = &variable_table.parent {
83
+ devalang_types::VariableTable {
84
+ variables: parent.variables.clone(),
85
+ parent: None,
86
+ }
87
+ } else {
88
+ variable_table.clone()
89
+ };
90
+
91
+ let pattern_str: String = pat.chars().filter(|c| !c.is_whitespace()).collect();
92
+ if pattern_str.is_empty() {
93
+ return (max_end_time, cursor_time);
94
+ }
95
+
96
+ let step_count = pattern_str.len() as f32;
97
+ let total_bar = 4.0 * base_duration;
98
+ let step_duration = total_bar / step_count;
99
+
100
+ let mut updated_max = max_end_time;
101
+
102
+ for (i, ch) in pattern_str.chars().enumerate() {
103
+ if ch == '-' {
104
+ continue;
105
+ }
106
+
107
+ let event_time = cursor_time + (i as f32) * step_duration;
108
+
109
+ let mut trigger_val = Value::String(target_entity.clone());
110
+ if let Some(val) = variable_table.variables.get(&target_entity) {
111
+ match val {
112
+ Value::Identifier(id) => {
113
+ if let Some(parent) = &variable_table.parent {
114
+ if let Some(v) = parent.get(id) {
115
+ trigger_val = v.clone();
116
+ }
117
+ } else if let Some(v) = variable_table.get(id) {
118
+ trigger_val = v.clone();
119
+ }
120
+ }
121
+ Value::Map(map) => {
122
+ if let Some(Value::String(src)) = map.get("entity") {
123
+ trigger_val = Value::String(src.clone());
124
+ } else if let Some(Value::Identifier(src)) = map.get("entity") {
125
+ trigger_val = Value::Identifier(src.clone());
126
+ }
127
+ }
128
+ Value::Sample(sample_src) => {
129
+ trigger_val = Value::Sample(sample_src.clone());
130
+ }
131
+ _ => {}
132
+ }
133
+ }
134
+
135
+ let (src, sample_length) = crate::core::audio::loader::trigger::load_trigger(
136
+ &trigger_val,
137
+ &Duration::Number(step_duration),
138
+ &None,
139
+ base_duration,
140
+ final_variable_table.clone(),
141
+ );
142
+
143
+ let play_length = step_duration.min(sample_length);
144
+
145
+ let trigger_src = match trigger_val.get("entity") {
146
+ Some(Value::String(s)) => s.clone(),
147
+ Some(Value::Identifier(id)) => id.clone(),
148
+ Some(Value::Statement(stmt)) => {
149
+ if let StatementKind::Trigger { entity, .. } = &stmt.kind {
150
+ entity.clone()
151
+ } else {
152
+ src.clone()
153
+ }
154
+ }
155
+ _ => src.clone(),
156
+ };
157
+
158
+ audio_engine.insert_sample(
159
+ &trigger_src,
160
+ event_time,
161
+ play_length,
162
+ None,
163
+ &final_variable_table,
164
+ );
165
+
166
+ let end_time = event_time + play_length;
167
+ if end_time > updated_max {
168
+ updated_max = end_time;
169
+ }
170
+ }
171
+
172
+ audio_engine.merge_with(local_engine);
173
+ return (updated_max.max(max_end_time), cursor_time);
174
+ }
175
+ }
176
+
177
+ // Function or group not found
178
+ }
179
+
180
+ (max_end_time, cursor_time)
181
+ }
182
+
183
+ fn find_group<'a>(
184
+ name: &str,
185
+ variable_table: &'a VariableTable,
186
+ global_store: &'a GlobalStore,
187
+ ) -> Option<&'a Statement> {
188
+ if let Some(Value::Statement(stmt_box)) = variable_table.get(name) {
189
+ if let StatementKind::Group = stmt_box.kind {
190
+ return Some(stmt_box);
191
+ }
192
+ }
193
+ if let Some(Value::Statement(stmt_box)) = global_store.variables.variables.get(name) {
194
+ if let StatementKind::Group = stmt_box.kind {
195
+ return Some(stmt_box);
196
+ }
197
+ }
198
+ None
199
+ }
200
+
201
+ fn find_pattern(
202
+ name: &str,
203
+ variable_table: &VariableTable,
204
+ global_store: &GlobalStore,
205
+ ) -> Option<Statement> {
206
+ use crate::core::parser::statement::Statement;
207
+ use crate::core::parser::statement::StatementKind;
208
+
209
+ if let Some(Value::Statement(stmt_box)) = variable_table.get(name) {
210
+ if let StatementKind::Pattern { .. } = stmt_box.kind {
211
+ return Some(*stmt_box.clone());
212
+ }
213
+ }
214
+
215
+ if let Some(val) = global_store.variables.variables.get(name) {
216
+ match val {
217
+ Value::Statement(stmt_box) => {
218
+ if let StatementKind::Pattern { .. } = stmt_box.kind {
219
+ return Some(*stmt_box.clone());
220
+ }
221
+ }
222
+ Value::Map(map) => {
223
+ if let Some(Value::String(_pat)) = map.get("pattern") {
224
+ // Rebuild a Pattern statement from stored map if possible
225
+ let stmt = Statement {
226
+ kind: StatementKind::Pattern {
227
+ name: name.to_string(),
228
+ target: map.get("target").and_then(|v| match v {
229
+ Value::String(s) => Some(s.clone()),
230
+ _ => None,
231
+ }),
232
+ },
233
+ value: Value::String(
234
+ map.get("pattern")
235
+ .and_then(|v| match v {
236
+ Value::String(s) => Some(s.clone()),
237
+ _ => None,
238
+ })
239
+ .unwrap_or_default(),
240
+ ),
241
+ indent: 0,
242
+ line: 0,
243
+ column: 0,
244
+ };
245
+ return Some(stmt);
246
+ }
247
+ }
248
+ _ => {}
249
+ }
250
+ }
251
+
252
+ None
253
+ }
@@ -0,0 +1,40 @@
1
+ use crate::core::parser::statement::{Statement, StatementKind};
2
+ use devalang_types::Value;
3
+ use devalang_utils::logger::{LogLevel, Logger};
4
+
5
+ pub fn interprete_tempo_statement(stmt: &Statement) -> Option<(f32, f32)> {
6
+ if let StatementKind::Tempo = &stmt.kind {
7
+ match &stmt.value {
8
+ Value::Number(bpm) => {
9
+ let bpm = { *bpm };
10
+ let duration = 60.0 / bpm;
11
+
12
+ return Some((bpm, duration));
13
+ }
14
+
15
+ Value::String(bpm_str) => {
16
+ if let Ok(bpm) = bpm_str.parse::<f32>() {
17
+ let duration = 60.0 / bpm;
18
+ return Some((bpm, duration));
19
+ }
20
+ }
21
+
22
+ Value::Identifier(bpm_ident) => {
23
+ if let Ok(bpm) = bpm_ident.parse::<f32>() {
24
+ let duration = 60.0 / bpm;
25
+ return Some((bpm, duration));
26
+ }
27
+ }
28
+
29
+ _ => {
30
+ let logger = Logger::new();
31
+ logger.log_message(
32
+ LogLevel::Warning,
33
+ format!("Invalid tempo value: {:?}", stmt.value).as_str(),
34
+ );
35
+ }
36
+ }
37
+ }
38
+
39
+ None
40
+ }