@devaloop/devalang 0.0.1-alpha.16-hotfix.1 → 0.0.1-alpha.17

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 (235) hide show
  1. package/.cargo/config.toml +2 -0
  2. package/.devalang +6 -10
  3. package/.github/workflows/ci.yml +19 -8
  4. package/Cargo.toml +18 -2
  5. package/README.md +80 -33
  6. package/docs/CHANGELOG.md +56 -0
  7. package/docs/ROADMAP.md +6 -3
  8. package/examples/index.deva +52 -35
  9. package/out-tsc/bin/index.d.ts +2 -0
  10. package/out-tsc/core/functions/index.d.ts +37 -0
  11. package/out-tsc/core/functions/index.js +76 -0
  12. package/out-tsc/core/index.d.ts +6 -0
  13. package/out-tsc/core/index.js +22 -0
  14. package/out-tsc/core/types/index.d.ts +4 -0
  15. package/out-tsc/core/types/index.js +20 -0
  16. package/out-tsc/core/types/plugin.d.ts +18 -0
  17. package/out-tsc/core/types/plugin.js +2 -0
  18. package/out-tsc/core/types/result.d.ts +27 -0
  19. package/out-tsc/core/types/result.js +2 -0
  20. package/out-tsc/core/types/statement.d.ts +106 -0
  21. package/out-tsc/core/types/statement.js +2 -0
  22. package/out-tsc/core/types/value.d.ts +43 -0
  23. package/out-tsc/core/types/value.js +2 -0
  24. package/out-tsc/index.d.ts +7 -0
  25. package/out-tsc/index.js +41 -2
  26. package/out-tsc/pkg/devalang_core.d.ts +7 -0
  27. package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +33 -0
  28. package/out-tsc/scripts/copy-wasm-dts.d.ts +1 -0
  29. package/out-tsc/scripts/copy-wasm-dts.js +73 -0
  30. package/out-tsc/scripts/postinstall.d.ts +1 -0
  31. package/out-tsc/scripts/postinstall.js +33 -23
  32. package/out-tsc/scripts/version/bump.d.ts +1 -0
  33. package/out-tsc/scripts/version/fetch.d.ts +1 -0
  34. package/out-tsc/scripts/version/index.d.ts +1 -0
  35. package/out-tsc/scripts/version/sync.d.ts +1 -0
  36. package/package.json +16 -4
  37. package/project-version.json +3 -3
  38. package/rust/cli/bank/api.rs +122 -0
  39. package/rust/cli/bank/commands.rs +275 -0
  40. package/rust/cli/bank/mod.rs +29 -0
  41. package/rust/cli/build/commands.rs +97 -0
  42. package/rust/cli/build/mod.rs +2 -0
  43. package/rust/cli/build/process.rs +146 -0
  44. package/rust/cli/{check.rs → check/mod.rs} +18 -31
  45. package/rust/cli/discover/commands.rs +253 -0
  46. package/rust/cli/discover/config.rs +111 -0
  47. package/rust/cli/discover/fs.rs +19 -0
  48. package/rust/cli/discover/install.rs +103 -0
  49. package/rust/cli/discover/metadata.rs +48 -0
  50. package/rust/cli/discover/mod.rs +5 -0
  51. package/rust/cli/{init.rs → init/commands.rs} +88 -87
  52. package/rust/cli/init/mod.rs +1 -0
  53. package/rust/{installer → cli/install}/addon.rs +5 -9
  54. package/rust/cli/install/bank.rs +53 -0
  55. package/rust/cli/{install.rs → install/commands.rs} +9 -9
  56. package/rust/{installer → cli/install}/mod.rs +2 -3
  57. package/rust/cli/install/plugin.rs +61 -0
  58. package/rust/cli/{login.rs → login/commands.rs} +8 -11
  59. package/rust/cli/login/mod.rs +1 -0
  60. package/rust/cli/mod.rs +2 -3
  61. package/rust/cli/{driver.rs → parser.rs} +19 -2
  62. package/rust/cli/play/commands.rs +324 -0
  63. package/rust/cli/play/io.rs +17 -0
  64. package/rust/cli/play/mod.rs +5 -0
  65. package/rust/cli/play/process.rs +150 -0
  66. package/rust/cli/play/realtime.rs +91 -0
  67. package/rust/cli/play/utils.rs +23 -0
  68. package/rust/cli/telemetry/commands.rs +22 -0
  69. package/rust/cli/telemetry/event_creator.rs +80 -0
  70. package/rust/cli/telemetry/mod.rs +3 -0
  71. package/rust/cli/telemetry/send.rs +51 -0
  72. package/rust/cli/{template.rs → template/commands.rs} +1 -1
  73. package/rust/cli/template/mod.rs +1 -0
  74. package/rust/cli/{update.rs → update/commands.rs} +6 -6
  75. package/rust/cli/update/mod.rs +1 -0
  76. package/rust/config/driver.rs +57 -72
  77. package/rust/config/mod.rs +1 -2
  78. package/rust/config/ops.rs +26 -0
  79. package/rust/config/settings.rs +60 -50
  80. package/rust/core/audio/engine/helpers.rs +146 -0
  81. package/rust/core/audio/engine/mod.rs +7 -0
  82. package/rust/core/audio/engine/sample.rs +298 -0
  83. package/rust/core/audio/engine/synth.rs +310 -0
  84. package/rust/core/audio/evaluator.rs +15 -12
  85. package/rust/core/audio/interpreter/arrow_call.rs +99 -24
  86. package/rust/core/audio/interpreter/call.rs +81 -60
  87. package/rust/core/audio/interpreter/condition.rs +3 -2
  88. package/rust/core/audio/interpreter/driver.rs +206 -151
  89. package/rust/core/audio/interpreter/let_.rs +1 -1
  90. package/rust/core/audio/interpreter/load.rs +2 -1
  91. package/rust/core/audio/interpreter/loop_.rs +7 -6
  92. package/rust/core/audio/interpreter/sleep.rs +2 -1
  93. package/rust/core/audio/interpreter/spawn.rs +45 -57
  94. package/rust/core/audio/interpreter/tempo.rs +31 -10
  95. package/rust/core/audio/interpreter/trigger.rs +2 -2
  96. package/rust/core/audio/loader/trigger.rs +4 -7
  97. package/rust/core/audio/player.rs +6 -0
  98. package/rust/core/audio/renderer.rs +5 -7
  99. package/rust/core/audio/special/env.rs +3 -1
  100. package/rust/core/audio/special/math.rs +4 -4
  101. package/rust/core/audio/special/modulator.rs +2 -2
  102. package/rust/core/builder/mod.rs +9 -3
  103. package/rust/core/debugger/lexer.rs +1 -1
  104. package/rust/core/debugger/mod.rs +6 -0
  105. package/rust/core/debugger/module.rs +4 -4
  106. package/rust/core/debugger/preprocessor.rs +1 -1
  107. package/rust/core/debugger/store.rs +2 -2
  108. package/rust/core/error/mod.rs +189 -0
  109. package/rust/core/lexer/handler/arrow.rs +1 -1
  110. package/rust/core/lexer/handler/at.rs +1 -1
  111. package/rust/core/lexer/handler/brace.rs +2 -2
  112. package/rust/core/lexer/handler/colon.rs +1 -1
  113. package/rust/core/lexer/handler/comment.rs +1 -1
  114. package/rust/core/lexer/handler/dot.rs +1 -1
  115. package/rust/core/lexer/handler/driver.rs +1 -1
  116. package/rust/core/lexer/handler/identifier.rs +1 -1
  117. package/rust/core/lexer/handler/mod.rs +1 -2
  118. package/rust/core/lexer/handler/number.rs +1 -1
  119. package/rust/core/lexer/handler/operator.rs +1 -1
  120. package/rust/core/lexer/handler/parenthesis.rs +2 -2
  121. package/rust/core/lexer/handler/slash.rs +1 -1
  122. package/rust/core/lexer/handler/string.rs +1 -1
  123. package/rust/core/lexer/mod.rs +22 -12
  124. package/rust/core/lexer/token.rs +90 -97
  125. package/rust/core/mod.rs +0 -1
  126. package/rust/core/parser/driver.rs +66 -13
  127. package/rust/core/parser/handler/arrow_call.rs +28 -8
  128. package/rust/core/parser/handler/at.rs +55 -21
  129. package/rust/core/parser/handler/bank.rs +14 -4
  130. package/rust/core/parser/handler/condition.rs +6 -3
  131. package/rust/core/parser/handler/dot.rs +2 -1
  132. package/rust/core/parser/handler/identifier/automate.rs +13 -16
  133. package/rust/core/parser/handler/identifier/call.rs +4 -4
  134. package/rust/core/parser/handler/identifier/emit.rs +9 -5
  135. package/rust/core/parser/handler/identifier/function.rs +20 -7
  136. package/rust/core/parser/handler/identifier/group.rs +11 -7
  137. package/rust/core/parser/handler/identifier/let_.rs +24 -9
  138. package/rust/core/parser/handler/identifier/mod.rs +6 -5
  139. package/rust/core/parser/handler/identifier/on.rs +16 -7
  140. package/rust/core/parser/handler/identifier/print.rs +6 -9
  141. package/rust/core/parser/handler/identifier/sleep.rs +12 -5
  142. package/rust/core/parser/handler/identifier/spawn.rs +4 -4
  143. package/rust/core/parser/handler/identifier/synth.rs +79 -9
  144. package/rust/core/parser/handler/loop_.rs +39 -14
  145. package/rust/core/parser/handler/tempo.rs +9 -5
  146. package/rust/core/parser/mod.rs +0 -1
  147. package/rust/core/parser/statement.rs +6 -137
  148. package/rust/core/plugin/loader.rs +41 -27
  149. package/rust/core/plugin/runner.rs +68 -17
  150. package/rust/core/preprocessor/loader.rs +155 -33
  151. package/rust/core/preprocessor/processor.rs +2 -2
  152. package/rust/core/preprocessor/resolver/bank.rs +6 -8
  153. package/rust/core/preprocessor/resolver/call.rs +20 -24
  154. package/rust/core/preprocessor/resolver/condition.rs +6 -8
  155. package/rust/core/preprocessor/resolver/driver.rs +14 -16
  156. package/rust/core/preprocessor/resolver/function.rs +6 -6
  157. package/rust/core/preprocessor/resolver/group.rs +6 -8
  158. package/rust/core/preprocessor/resolver/loop_.rs +8 -10
  159. package/rust/core/preprocessor/resolver/spawn.rs +19 -23
  160. package/rust/core/preprocessor/resolver/synth.rs +6 -8
  161. package/rust/core/preprocessor/resolver/tempo.rs +6 -8
  162. package/rust/core/preprocessor/resolver/trigger.rs +22 -19
  163. package/rust/core/preprocessor/resolver/value.rs +99 -4
  164. package/rust/core/store/export.rs +28 -28
  165. package/rust/core/store/function.rs +6 -0
  166. package/rust/core/store/global.rs +7 -1
  167. package/rust/core/store/import.rs +28 -28
  168. package/rust/core/store/variable.rs +1 -1
  169. package/rust/core/utils/mod.rs +0 -1
  170. package/rust/lib.rs +102 -9
  171. package/rust/main.rs +156 -45
  172. package/rust/types/Cargo.toml +8 -0
  173. package/rust/types/src/addons.rs +55 -0
  174. package/rust/types/src/ast.rs +198 -0
  175. package/rust/types/src/config.rs +74 -0
  176. package/rust/types/src/lib.rs +12 -0
  177. package/rust/types/src/telemetry.rs +85 -0
  178. package/rust/utils/Cargo.toml +23 -0
  179. package/rust/utils/{error.rs → src/error.rs} +186 -200
  180. package/rust/utils/src/file.rs +94 -0
  181. package/rust/utils/src/first_usage.rs +97 -0
  182. package/rust/utils/{mod.rs → src/lib.rs} +1 -1
  183. package/rust/utils/{logger.rs → src/logger.rs} +17 -12
  184. package/rust/utils/src/path.rs +88 -0
  185. package/rust/utils/src/signature.rs +41 -0
  186. package/rust/utils/{spinner.rs → src/spinner.rs} +3 -5
  187. package/rust/utils/src/version.rs +27 -0
  188. package/rust/utils/{watcher.rs → src/watcher.rs} +13 -1
  189. package/rust/web/api.rs +5 -0
  190. package/rust/web/cdn.rs +34 -0
  191. package/templates/minimal/README.md +98 -54
  192. package/templates/welcome/README.md +98 -54
  193. package/templates/welcome/src/index.deva +56 -8
  194. package/templates/welcome/src/variables.deva +2 -4
  195. package/tests/rust/TODO.md +0 -0
  196. package/tests/typescript/index.spec.ts +136 -0
  197. package/tests/typescript/playhead.spec.ts +36 -0
  198. package/tests/typescript/render_e2e.spec.ts +77 -0
  199. package/tsconfig.json +1 -1
  200. package/typescript/core/functions/index.ts +83 -0
  201. package/typescript/core/index.ts +6 -0
  202. package/typescript/core/types/index.ts +4 -0
  203. package/typescript/core/types/plugin.ts +19 -0
  204. package/typescript/core/types/result.ts +29 -0
  205. package/typescript/core/types/statement.ts +47 -0
  206. package/typescript/core/types/value.ts +29 -0
  207. package/typescript/index.ts +7 -2
  208. package/typescript/pkg/devalang_core.d.ts +4 -0
  209. package/typescript/scripts/copy-wasm-dts.ts +41 -0
  210. package/typescript/scripts/postinstall.ts +45 -32
  211. package/rust/cli/bank.rs +0 -462
  212. package/rust/cli/build.rs +0 -252
  213. package/rust/cli/generator.rs +0 -1
  214. package/rust/cli/play.rs +0 -1123
  215. package/rust/cli/telemetry.rs +0 -19
  216. package/rust/common/api.rs +0 -5
  217. package/rust/common/cdn.rs +0 -5
  218. package/rust/config/loader.rs +0 -165
  219. package/rust/config/stats.rs +0 -257
  220. package/rust/core/audio/engine.rs +0 -696
  221. package/rust/core/shared/bank.rs +0 -21
  222. package/rust/core/shared/duration.rs +0 -9
  223. package/rust/core/shared/mod.rs +0 -3
  224. package/rust/core/shared/value.rs +0 -35
  225. package/rust/core/utils/validation.rs +0 -35
  226. package/rust/installer/bank.rs +0 -62
  227. package/rust/installer/plugin.rs +0 -54
  228. package/rust/installer/utils.rs +0 -56
  229. package/rust/utils/file.rs +0 -38
  230. package/rust/utils/first_usage.rs +0 -76
  231. package/rust/utils/signature.rs +0 -19
  232. package/rust/utils/telemetry.rs +0 -292
  233. package/rust/utils/version.rs +0 -15
  234. /package/rust/{common → web}/mod.rs +0 -0
  235. /package/rust/{common → web}/sso.rs +0 -0
@@ -1,7 +1,8 @@
1
+ use devalang_types::Value;
2
+
1
3
  use crate::core::{
2
4
  audio::{engine::AudioEngine, interpreter::driver::execute_audio_block},
3
5
  parser::statement::{Statement, StatementKind},
4
- shared::value::Value,
5
6
  store::{function::FunctionTable, global::GlobalStore, variable::VariableTable},
6
7
  };
7
8
 
@@ -16,71 +17,58 @@ pub fn interprete_spawn_statement(
16
17
  max_end_time: f32,
17
18
  cursor_time: f32,
18
19
  ) -> (f32, f32) {
19
- match &stmt.kind {
20
- StatementKind::Spawn { name, args } => {
21
- let mut local_engine = AudioEngine::new(audio_engine.module_name.clone());
20
+ if let StatementKind::Spawn { name, args } = &stmt.kind {
21
+ let mut local_engine = AudioEngine::new(audio_engine.module_name.clone());
22
22
 
23
- // Function case
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
- }
23
+ // Function case
24
+ if let Some(func) = functions.functions.get(name) {
25
+ if func.parameters.len() != args.len() {
26
+ return (max_end_time, cursor_time);
27
+ }
34
28
 
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
- }
29
+ let mut local_vars = VariableTable::with_parent(variable_table.clone());
30
+ for (param, arg) in func.parameters.iter().zip(args) {
31
+ local_vars.set(param.clone(), arg.clone());
32
+ }
39
33
 
40
- let (spawn_max, _) = execute_audio_block(
41
- &mut local_engine,
42
- global_store,
43
- local_vars,
44
- functions.clone(),
45
- &func.body,
46
- base_bpm,
47
- base_duration,
48
- 0.0,
49
- 0.0,
50
- );
34
+ let (spawn_max, _) = execute_audio_block(
35
+ &mut local_engine,
36
+ global_store,
37
+ local_vars,
38
+ functions.clone(),
39
+ &func.body,
40
+ base_bpm,
41
+ base_duration,
42
+ 0.0,
43
+ 0.0,
44
+ );
51
45
 
52
- audio_engine.merge_with(local_engine);
53
- return (spawn_max.max(max_end_time), cursor_time);
54
- }
46
+ audio_engine.merge_with(local_engine);
47
+ return (spawn_max.max(max_end_time), cursor_time);
48
+ }
55
49
 
56
- // Group case
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,
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
- }
50
+ // Group case
51
+ if let Some(group_stmt) = find_group(name, variable_table, global_store) {
52
+ if let Value::Map(map) = &group_stmt.value {
53
+ if let Some(Value::Block(body)) = map.get("body") {
54
+ let (spawn_max, _) = execute_audio_block(
55
+ &mut local_engine,
56
+ global_store,
57
+ variable_table.clone(),
58
+ functions.clone(),
59
+ body,
60
+ base_bpm,
61
+ base_duration,
62
+ 0.0,
63
+ 0.0,
64
+ );
65
+ audio_engine.merge_with(local_engine);
66
+ return (spawn_max.max(max_end_time), cursor_time);
74
67
  }
75
68
  }
76
-
77
- eprintln!("❌ Function or group '{}' not found", name);
78
69
  }
79
70
 
80
- _ => eprintln!(
81
- "❌ interprete_spawn_statement expected Spawn, got {:?}",
82
- stmt.kind
83
- ),
71
+ // Function or group not found
84
72
  }
85
73
 
86
74
  (max_end_time, cursor_time)
@@ -1,17 +1,38 @@
1
- use crate::core::{
2
- parser::statement::{Statement, StatementKind},
3
- shared::value::Value,
4
- };
1
+ use crate::core::parser::statement::{Statement, StatementKind};
2
+ use devalang_types::Value;
3
+ use devalang_utils::logger::{LogLevel, Logger};
5
4
 
6
5
  pub fn interprete_tempo_statement(stmt: &Statement) -> Option<(f32, f32)> {
7
6
  if let StatementKind::Tempo = &stmt.kind {
8
- if let Value::Number(bpm) = &stmt.value {
9
- let bpm = *bpm as f32;
10
- let duration = 60.0 / bpm;
7
+ match &stmt.value {
8
+ Value::Number(bpm) => {
9
+ let bpm = { *bpm };
10
+ let duration = 60.0 / bpm;
11
11
 
12
- return Some((bpm, duration));
13
- } else {
14
- eprintln!("❌ Invalid tempo value: {:?}", stmt.value);
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
+ }
15
36
  }
16
37
  }
17
38
 
@@ -3,10 +3,10 @@ use std::collections::HashMap;
3
3
  use crate::core::{
4
4
  audio::{engine::AudioEngine, loader::trigger::load_trigger},
5
5
  parser::statement::{Statement, StatementKind},
6
- shared::{duration::Duration, value::Value},
7
6
  store::variable::VariableTable,
8
7
  };
9
- use crate::utils::logger::Logger;
8
+ use devalang_types::{Duration, Value};
9
+ use devalang_utils::logger::Logger;
10
10
 
11
11
  pub fn interprete_trigger_statement(
12
12
  stmt: &Statement,
@@ -1,8 +1,5 @@
1
- use crate::core::{
2
- parser::statement::StatementKind,
3
- shared::{duration::Duration, value::Value},
4
- store::variable::VariableTable,
5
- };
1
+ use crate::core::{parser::statement::StatementKind, store::variable::VariableTable};
2
+ use devalang_types::{Duration, Value};
6
3
 
7
4
  pub fn load_trigger(
8
5
  trigger: &Value,
@@ -24,9 +21,9 @@ pub fn load_trigger(
24
21
 
25
22
  Value::Map(map) => {
26
23
  if let Some(Value::String(src)) = map.get("entity") {
27
- trigger_path = format!("devalang://bank/{}", src.to_string());
24
+ trigger_path = format!("devalang://bank/{}", src);
28
25
  } else if let Some(Value::Identifier(src)) = map.get("entity") {
29
- trigger_path = format!("devalang://bank/{}", src.to_string());
26
+ trigger_path = format!("devalang://bank/{}", src);
30
27
  } else {
31
28
  eprintln!(
32
29
  "❌ Trigger map must contain an 'entity' key with a string or identifier value."
@@ -8,6 +8,12 @@ pub struct AudioPlayer {
8
8
  last_path: Option<String>,
9
9
  }
10
10
 
11
+ impl Default for AudioPlayer {
12
+ fn default() -> Self {
13
+ Self::new()
14
+ }
15
+ }
16
+
11
17
  impl AudioPlayer {
12
18
  pub fn new() -> Self {
13
19
  let (stream, handle) = OutputStream::try_default().unwrap();
@@ -1,11 +1,9 @@
1
- use crate::{
2
- core::{
3
- audio::{engine::AudioEngine, interpreter::driver::run_audio_program},
4
- parser::statement::Statement,
5
- store::global::GlobalStore,
6
- },
7
- utils::logger::{LogLevel, Logger},
1
+ use crate::core::{
2
+ audio::{engine::AudioEngine, interpreter::driver::run_audio_program},
3
+ parser::statement::Statement,
4
+ store::global::GlobalStore,
8
5
  };
6
+ use devalang_utils::logger::{LogLevel, Logger};
9
7
  use std::collections::HashMap;
10
8
 
11
9
  pub fn render_audio_with_modules(
@@ -1,3 +1,5 @@
1
+ use devalang_types::Value;
2
+
1
3
  use crate::core::store::variable::VariableTable;
2
4
  use std::sync::OnceLock;
3
5
  use std::time::{SystemTime, UNIX_EPOCH};
@@ -36,7 +38,7 @@ pub fn resolve_atom_or_var(atom: &str, vars: &VariableTable, bpm: f32, beat: f32
36
38
  if let Ok(n) = atom.parse::<f32>() {
37
39
  return Some(n);
38
40
  }
39
- if let Some(crate::core::shared::value::Value::Number(n)) = vars.get(atom) {
41
+ if let Some(Value::Number(n)) = vars.get(atom) {
40
42
  return Some(*n);
41
43
  }
42
44
  None
@@ -25,12 +25,12 @@ fn parse_top_level_args(s: &str) -> Vec<&str> {
25
25
 
26
26
  fn eval_math_func(func: &str, args: &[f32], fallback_seed: f32) -> Option<f32> {
27
27
  match func {
28
- "sin" => args.get(0).copied().map(f32::sin),
29
- "cos" => args.get(0).copied().map(f32::cos),
28
+ "sin" => args.first().copied().map(f32::sin),
29
+ "cos" => args.first().copied().map(f32::cos),
30
30
  "random" => {
31
31
  // deterministic pseudo-random based on provided seed or a fallback session seed
32
- let seed = args.get(0).copied().unwrap_or(fallback_seed);
33
- let x = (seed * 12.9898).sin() * 43758.5453;
32
+ let seed = args.first().copied().unwrap_or(fallback_seed);
33
+ let x = (seed * 12.9898).sin() * 43_758.547;
34
34
  Some((x.fract() * 2.0 - 1.0).clamp(-1.0, 1.0))
35
35
  }
36
36
  "lerp" => {
@@ -44,11 +44,11 @@ fn adsr_envelope_value_t(attack: f32, decay: f32, sustain: f32, release: f32, t:
44
44
  fn eval_mod_func(func: &str, args: &[f32], beat: f32) -> Option<f32> {
45
45
  match func {
46
46
  "lfo.sine" => {
47
- let rate = args.get(0).copied().unwrap_or(1.0);
47
+ let rate = args.first().copied().unwrap_or(1.0);
48
48
  Some(lfo_sine(rate, beat))
49
49
  }
50
50
  "lfo.tri" | "lfo.triangle" => {
51
- let rate = args.get(0).copied().unwrap_or(1.0);
51
+ let rate = args.first().copied().unwrap_or(1.0);
52
52
  Some(lfo_triangle(rate, beat))
53
53
  }
54
54
  // ADSR envelope normalized over t in [0,1]
@@ -1,12 +1,18 @@
1
1
  use crate::core::audio::renderer::render_audio_with_modules;
2
2
  use crate::core::parser::statement::Statement;
3
3
  use crate::core::store::global::GlobalStore;
4
- use crate::utils::logger::Logger;
4
+ use devalang_utils::logger::Logger;
5
5
  use std::io::Write;
6
6
  use std::{collections::HashMap, fs::create_dir_all};
7
7
 
8
8
  pub struct Builder {}
9
9
 
10
+ impl Default for Builder {
11
+ fn default() -> Self {
12
+ Self::new()
13
+ }
14
+ }
15
+
10
16
  impl Builder {
11
17
  pub fn new() -> Self {
12
18
  Builder {}
@@ -46,7 +52,7 @@ impl Builder {
46
52
  let logger = Logger::new();
47
53
 
48
54
  let audio_engines =
49
- render_audio_with_modules(modules.clone(), &normalized_output_dir, global_store);
55
+ render_audio_with_modules(modules.clone(), normalized_output_dir, global_store);
50
56
 
51
57
  create_dir_all(format!("{}/audio", normalized_output_dir))
52
58
  .expect("Failed to create audio directory");
@@ -54,7 +60,7 @@ impl Builder {
54
60
  for (module_name, mut audio_engine) in audio_engines {
55
61
  let formatted_module_name = module_name
56
62
  .split('/')
57
- .last()
63
+ .next_back()
58
64
  .unwrap_or(&module_name)
59
65
  .replace(".deva", "");
60
66
 
@@ -20,7 +20,7 @@ pub fn write_lexer_log_file(
20
20
  content.push_str(&format!("{:?}\n", token));
21
21
  }
22
22
 
23
- content.push_str("\n");
23
+ content.push('\n');
24
24
  }
25
25
 
26
26
  debugger.write_log_file(&log_directory, file_name, &content);
@@ -7,6 +7,12 @@ use std::io::Write;
7
7
 
8
8
  pub struct Debugger {}
9
9
 
10
+ impl Default for Debugger {
11
+ fn default() -> Self {
12
+ Self::new()
13
+ }
14
+ }
15
+
10
16
  impl Debugger {
11
17
  pub fn new() -> Self {
12
18
  Debugger {}
@@ -13,7 +13,7 @@ pub fn write_module_variable_log_file(
13
13
  let mut content = String::new();
14
14
  let module_name = module_path
15
15
  .split('/')
16
- .last()
16
+ .next_back()
17
17
  .unwrap_or("index")
18
18
  .replace(".deva", "");
19
19
 
@@ -24,7 +24,7 @@ pub fn write_module_variable_log_file(
24
24
  content.push_str(&format!("{:?} = {:?}\n", var_name, var_data));
25
25
  }
26
26
 
27
- content.push_str("\n");
27
+ content.push('\n');
28
28
 
29
29
  debugger.write_log_file(&log_directory, "variables.log", &content);
30
30
  }
@@ -38,7 +38,7 @@ pub fn write_module_function_log_file(
38
38
  let mut content = String::new();
39
39
  let module_name = module_path
40
40
  .split('/')
41
- .last()
41
+ .next_back()
42
42
  .unwrap_or("index")
43
43
  .replace(".deva", "");
44
44
 
@@ -49,7 +49,7 @@ pub fn write_module_function_log_file(
49
49
  content.push_str(&format!("{:?} = {:?}\n", func_name, func_data));
50
50
  }
51
51
 
52
- content.push_str("\n");
52
+ content.push('\n');
53
53
 
54
54
  debugger.write_log_file(&log_directory, "functions.log", &content);
55
55
  }
@@ -20,7 +20,7 @@ pub fn write_preprocessor_log_file(
20
20
  content.push_str(&format!("{:?}\n", stmt));
21
21
  }
22
22
 
23
- content.push_str("\n");
23
+ content.push('\n');
24
24
  }
25
25
 
26
26
  debugger.write_log_file(&log_directory, file_name, &content);
@@ -15,7 +15,7 @@ pub fn write_variables_log_file(output_dir: &str, file_name: &str, variables: Va
15
15
  content.push_str(&format!("{:?} = {:?}\n", var_name, var_data));
16
16
  }
17
17
 
18
- content.push_str("\n");
18
+ content.push('\n');
19
19
 
20
20
  debugger.write_log_file(&log_directory, file_name, &content);
21
21
  }
@@ -34,7 +34,7 @@ pub fn write_function_log_file(output_dir: &str, file_name: &str, functions: Fun
34
34
  ));
35
35
  }
36
36
 
37
- content.push_str("\n");
37
+ content.push('\n');
38
38
 
39
39
  debugger.write_log_file(&log_directory, file_name, &content);
40
40
  }
@@ -2,6 +2,7 @@ use crate::core::parser::{
2
2
  driver::Parser,
3
3
  statement::{Statement, StatementKind},
4
4
  };
5
+ use devalang_types::Value;
5
6
  use serde::{Deserialize, Serialize};
6
7
 
7
8
  pub struct ErrorHandler {
@@ -38,6 +39,12 @@ pub struct Error {
38
39
  pub column: usize,
39
40
  }
40
41
 
42
+ impl Default for ErrorHandler {
43
+ fn default() -> Self {
44
+ Self::new()
45
+ }
46
+ }
47
+
41
48
  impl ErrorHandler {
42
49
  pub fn new() -> Self {
43
50
  Self { errors: Vec::new() }
@@ -78,3 +85,185 @@ impl ErrorHandler {
78
85
  }
79
86
  }
80
87
  }
88
+
89
+ /// Collects errors recursively from statements (mirrors old utils implementation).
90
+ pub fn collect_errors_recursively(statements: &[Statement]) -> Vec<ErrorResult> {
91
+ let mut errors: Vec<ErrorResult> = Vec::new();
92
+
93
+ for stmt in statements {
94
+ match &stmt.kind {
95
+ StatementKind::Unknown => {
96
+ errors.push(ErrorResult {
97
+ message: format!("Unknown statement at line {}:{}", stmt.line, stmt.column),
98
+ line: stmt.line,
99
+ column: stmt.column,
100
+ severity: Severity::Warning,
101
+ stack: vec![StackFrame {
102
+ module: None,
103
+ context: Some("Unknown".to_string()),
104
+ line: stmt.line,
105
+ column: stmt.column,
106
+ }],
107
+ });
108
+ }
109
+ StatementKind::Error { message } => {
110
+ errors.push(ErrorResult {
111
+ message: message.clone(),
112
+ line: stmt.line,
113
+ column: stmt.column,
114
+ severity: Severity::Critical,
115
+ stack: vec![StackFrame {
116
+ module: None,
117
+ context: Some("Error".to_string()),
118
+ line: stmt.line,
119
+ column: stmt.column,
120
+ }],
121
+ });
122
+ }
123
+ StatementKind::Loop => {
124
+ if let Some(body_statements) = extract_loop_body_statements(&stmt.value) {
125
+ let nested = collect_errors_recursively(body_statements);
126
+ errors.extend(nested.into_iter().map(|mut e| {
127
+ e.stack.insert(
128
+ 0,
129
+ StackFrame {
130
+ module: None,
131
+ context: Some("loop".to_string()),
132
+ line: stmt.line,
133
+ column: stmt.column,
134
+ },
135
+ );
136
+ e
137
+ }));
138
+ }
139
+ }
140
+ _ => {}
141
+ }
142
+ }
143
+
144
+ errors
145
+ }
146
+
147
+ fn extract_loop_body_statements(value: &Value) -> Option<&[Statement]> {
148
+ if let Value::Map(map) = value {
149
+ if let Some(Value::Block(statements)) = map.get("body") {
150
+ return Some(statements);
151
+ }
152
+ }
153
+ None
154
+ }
155
+
156
+ pub fn partition_errors(errors: Vec<ErrorResult>) -> (Vec<ErrorResult>, Vec<ErrorResult>) {
157
+ let mut warnings = Vec::new();
158
+ let mut criticals = Vec::new();
159
+ for e in errors {
160
+ match e.severity {
161
+ Severity::Warning => warnings.push(e),
162
+ Severity::Critical => criticals.push(e),
163
+ }
164
+ }
165
+ (warnings, criticals)
166
+ }
167
+
168
+ pub fn log_errors_with_stack(prefix: &str, warnings: &[ErrorResult], criticals: &[ErrorResult]) {
169
+ use devalang_utils::logger::LogLevel;
170
+ use devalang_utils::logger::Logger;
171
+
172
+ let logger = Logger::new();
173
+ if !warnings.is_empty() {
174
+ logger.log_message(
175
+ LogLevel::Warning,
176
+ &format!("{}: {} warning(s)", prefix, warnings.len()),
177
+ );
178
+ for w in warnings {
179
+ logger.log_message(LogLevel::Warning, &format!("- {}", w.message));
180
+ if let Some(frame) = w.stack.first() {
181
+ let module = frame.module.clone().unwrap_or_default();
182
+ logger.log_message(
183
+ LogLevel::Debug,
184
+ &format!(
185
+ " ↳ {}:{}:{} {}",
186
+ module,
187
+ frame.line,
188
+ frame.column,
189
+ frame.context.clone().unwrap_or_default()
190
+ ),
191
+ );
192
+ }
193
+ if w.stack.len() > 1 {
194
+ for (i, f) in w.stack.iter().enumerate().skip(1) {
195
+ let module = f.module.clone().unwrap_or_default();
196
+ logger.log_message(
197
+ LogLevel::Debug,
198
+ &format!(
199
+ " #{} {}:{}:{} {}",
200
+ i,
201
+ module,
202
+ f.line,
203
+ f.column,
204
+ f.context.clone().unwrap_or_default()
205
+ ),
206
+ );
207
+ }
208
+ }
209
+ }
210
+ }
211
+ if !criticals.is_empty() {
212
+ logger.log_message(
213
+ LogLevel::Error,
214
+ &format!("{}: {} critical error(s)", prefix, criticals.len()),
215
+ );
216
+ for c in criticals {
217
+ logger.log_message(LogLevel::Error, &format!("- {}", c.message));
218
+ if let Some(frame) = c.stack.first() {
219
+ let module = frame.module.clone().unwrap_or_default();
220
+ logger.log_message(
221
+ LogLevel::Error,
222
+ &format!(
223
+ " ↳ {}:{}:{} {}",
224
+ module,
225
+ frame.line,
226
+ frame.column,
227
+ frame.context.clone().unwrap_or_default()
228
+ ),
229
+ );
230
+ }
231
+ if c.stack.len() > 1 {
232
+ for (i, f) in c.stack.iter().enumerate().skip(1) {
233
+ let module = f.module.clone().unwrap_or_default();
234
+ logger.log_message(
235
+ LogLevel::Error,
236
+ &format!(
237
+ " #{} {}:{}:{} {}",
238
+ i,
239
+ module,
240
+ f.line,
241
+ f.column,
242
+ f.context.clone().unwrap_or_default()
243
+ ),
244
+ );
245
+ }
246
+ }
247
+ }
248
+ }
249
+ }
250
+
251
+ /// Collects errors from all modules and annotates stack frames with module names.
252
+ pub fn collect_all_errors_with_modules(
253
+ statements_by_module: &std::collections::HashMap<String, Vec<Statement>>,
254
+ ) -> Vec<ErrorResult> {
255
+ let mut all: Vec<ErrorResult> = Vec::new();
256
+ for (module, stmts) in statements_by_module.iter() {
257
+ let mut errs = collect_errors_recursively(stmts);
258
+ for e in errs.iter_mut() {
259
+ // annotate first stack frame module if missing
260
+ if let Some(first) = e.stack.first_mut() {
261
+ if first.module.is_none() {
262
+ first.module = Some(module.clone());
263
+ }
264
+ }
265
+ }
266
+ all.extend(errs.into_iter());
267
+ }
268
+ all
269
+ }
@@ -4,7 +4,7 @@ pub fn handle_arrow_lexer(
4
4
  ch: char,
5
5
  chars: &mut std::iter::Peekable<std::str::Chars>,
6
6
  current_indent: &mut usize,
7
- _indent_stack: &mut Vec<usize>,
7
+ _indent_stack: &mut [usize],
8
8
  tokens: &mut Vec<Token>,
9
9
  line: &mut usize,
10
10
  column: &mut usize,
@@ -4,7 +4,7 @@ pub fn handle_at_lexer(
4
4
  ch: char,
5
5
  _chars: &mut std::iter::Peekable<std::str::Chars>,
6
6
  current_indent: &mut usize,
7
- _indent_stack: &mut Vec<usize>,
7
+ _indent_stack: &mut [usize],
8
8
  tokens: &mut Vec<Token>,
9
9
  line: &mut usize,
10
10
  column: &mut usize,
@@ -4,7 +4,7 @@ pub fn handle_rbrace_lexer(
4
4
  ch: char,
5
5
  _chars: &mut std::iter::Peekable<std::str::Chars>,
6
6
  current_indent: &mut usize,
7
- _indent_stack: &mut Vec<usize>,
7
+ _indent_stack: &mut [usize],
8
8
  tokens: &mut Vec<Token>,
9
9
  line: &mut usize,
10
10
  column: &mut usize,
@@ -24,7 +24,7 @@ pub fn handle_lbrace_lexer(
24
24
  ch: char,
25
25
  _chars: &mut std::iter::Peekable<std::str::Chars>,
26
26
  current_indent: &mut usize,
27
- _indent_stack: &mut Vec<usize>,
27
+ _indent_stack: &mut [usize],
28
28
  tokens: &mut Vec<Token>,
29
29
  line: &mut usize,
30
30
  column: &mut usize,